Elysia Tools
Navigation
Objective-C
macOS Multithreading Objective-C Samples
macOS Objective-C multithreading examples including NSThread, NSOperationQueue, Grand Central Dispatch, and synchronization primitives
Samples
Entries inside this sample collection
NSThread Basics
Create and manage threads using NSThread with detach, init, and synchronization
Difficulty
5/10
Estimated time
25 min
Tags
objectivec, macos, multithreading, nsthread
Prerequisites
Objective-C basics, Foundation framework
// macOS Objective-C NSThread Basics
// Using Foundation framework
#import <Foundation/Foundation.h>
// MARK: - 1. Creating Threads with NSThread
@interface ThreadWorker : NSObject
// Worker method that runs on separate thread
- (void)doWork {
@autoreleasepool {
NSLog(@"[Thread] Work started on thread: %@", [NSThread currentThread]);
for (int i = 0; i < 5; i++) {
NSLog(@"[Thread] Working... %d", i + 1);
[NSThread sleepForTimeInterval:0.5];
}
NSLog(@"[Thread] Work completed");
}
}
// Worker method with parameters
- (void)doWorkWithObject:(id)object {
@autoreleasepool {
NSString *taskName = (NSString *)object;
NSLog(@"[Thread] Task '%@' started on thread: %@", taskName, [NSThread currentThread]);
for (int i = 0; i < 3; i++) {
NSLog(@"[Thread] %@ - Step %d", taskName, i + 1);
[NSThread sleepForTimeInterval:0.3];
}
NSLog(@"[Thread] Task '%@' completed", taskName);
}
}
@end
// MARK: - 2. Thread with Custom Properties
@interface CustomThread : NSThread
@property (nonatomic, strong) NSString *taskName;
@property (nonatomic, assign) NSInteger iterations;
- (instancetype)initWithTaskName:(NSString *)name iterations:(NSInteger)iterations;
@end
@implementation CustomThread
- (instancetype)initWithTaskName:(NSString *)name iterations:(NSInteger)iterations {
self = [super init];
if (self) {
_taskName = name;
_iterations = iterations;
}
return self;
}
- (void)main {
@autoreleasepool {
NSLog(@"[CustomThread] %@ started", self.taskName);
for (NSInteger i = 0; i < self.iterations && !self.isCancelled; i++) {
NSLog(@"[CustomThread] %@ - Iteration %ld", self.taskName, (long)(i + 1));
[NSThread sleepForTimeInterval:0.2];
}
if (self.isCancelled) {
NSLog(@"[CustomThread] %@ was cancelled", self.taskName);
} else {
NSLog(@"[CustomThread] %@ completed", self.taskName);
}
}
}
@end
// MARK: - 3. Thread Synchronization
@interface SynchronizedWorker : NSObject
@property (nonatomic, strong) NSMutableArray *sharedArray;
@property (nonatomic, strong) NSLock *arrayLock;
- (instancetype)init;
- (void)addToArray:(NSString *)value;
- (void)printArray;
@end
@implementation SynchronizedWorker
- (instancetype)init {
self = [super init];
if (self) {
_sharedArray = [NSMutableArray array];
_arrayLock = [[NSLock alloc] init];
}
return self;
}
- (void)addToArray:(NSString *)value {
[self.arrayLock lock];
@try {
[self.sharedArray addObject:value];
NSLog(@"Added: %@", value);
} @finally {
[self.arrayLock unlock];
}
}
- (void)printArray {
[self.arrayLock lock];
@try {
NSLog(@"Array contents: %@", self.sharedArray);
} @finally {
[self.arrayLock unlock];
}
}
@end
// MARK: - 4. Thread Communication
@interface ProducerConsumer : NSObject
@property (nonatomic, strong) NSMutableArray *buffer;
@property (nonatomic, strong) NSCondition *condition;
@property (nonatomic, assign) NSInteger bufferSize;
- (instancetype)initWithBufferSize:(NSInteger)size;
- (void)produce:(NSString *)item;
- (NSString *)consume;
@end
@implementation ProducerConsumer
- (instancetype)initWithBufferSize:(NSInteger)size {
self = [super init];
if (self) {
_buffer = [NSMutableArray array];
_condition = [[NSCondition alloc] init];
_bufferSize = size;
}
return self;
}
- (void)produce:(NSString *)item {
[self.condition lock];
while ([self.buffer count] >= self.bufferSize) {
NSLog(@"Buffer full, producer waiting...");
[self.condition wait];
}
[self.buffer addObject:item];
NSLog(@"Produced: %@ (buffer size: %lu)", item, (unsigned long)[self.buffer count]);
[self.condition signal];
[self.condition unlock];
}
- (NSString *)consume {
[self.condition lock];
while ([self.buffer count] == 0) {
NSLog(@"Buffer empty, consumer waiting...");
[self.condition wait];
}
NSString *item = [self.buffer firstObject];
[self.buffer removeObjectAtIndex:0];
NSLog(@"Consumed: %@ (buffer size: %lu)", item, (unsigned long)[self.buffer count]);
[self.condition signal];
[self.condition unlock];
return item;
}
@end
// MARK: - Main Demonstration
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"=== macOS Objective-C NSThread Examples ===\n");
// 1. Detached thread
NSLog(@"--- 1. Detached New Thread ---");
ThreadWorker *worker1 = [[ThreadWorker alloc] init];
[NSThread detachNewThreadSelector:@selector(doWork)
toTarget:worker1
withObject:nil];
[NSThread sleepForTimeInterval:3.0];
// 2. Thread with object parameter
NSLog(@"\n--- 2. Thread with Object Parameter ---");
ThreadWorker *worker2 = [[ThreadWorker alloc] init];
[NSThread detachNewThreadSelector:@selector(doWorkWithObject:)
toTarget:worker2
withObject:@"Task A"];
[NSThread detachNewThreadSelector:@selector(doWorkWithObject:)
toTarget:worker2
withObject:@"Task B"];
[NSThread sleepForTimeInterval:2.0];
// 3. Custom thread instance
NSLog(@"\n--- 3. Custom Thread Instance ---");
CustomThread *thread1 = [[CustomThread alloc] initWithTaskName:@"Custom Task 1" iterations:5];
CustomThread *thread2 = [[CustomThread alloc] initWithTaskName:@"Custom Task 2" iterations:3];
[thread1 start];
[thread2 start];
// Wait for threads to complete
while (thread1.isExecuting || thread2.isExecuting) {
[NSThread sleepForTimeInterval:0.1];
}
// 4. Thread cancellation
NSLog(@"\n--- 4. Thread Cancellation ---");
CustomThread *longThread = [[CustomThread alloc] initWithTaskName:@"Long Task" iterations:100];
[longThread start];
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Cancelling long task...");
[longThread cancel];
// Wait for cancellation
while (longThread.isExecuting) {
[NSThread sleepForTimeInterval:0.1];
}
// 5. Synchronized access
NSLog(@"\n--- 5. Synchronized Access ---");
SynchronizedWorker *syncWorker = [[SynchronizedWorker alloc] init];
for (int i = 0; i < 5; i++) {
NSString *value = [NSString stringWithFormat:@"Item-%d", i];
[NSThread detachNewThreadSelector:@selector(addToArray:)
toTarget:syncWorker
withObject:value];
}
[NSThread sleepForTimeInterval:1.0];
[syncWorker printArray];
// 6. Producer-consumer pattern
NSLog(@"\n--- 6. Producer-Consumer Pattern ---");
ProducerConsumer *pc = [[ProducerConsumer alloc] initWithBufferSize:3];
// Producer thread
[NSThread detachNewThreadSelector:@selector(producerThread) toTarget:pc withObject:nil];
// Consumer thread
[NSThread detachNewThreadSelector:@selector(consumerThread) toTarget:pc withObject:nil];
[NSThread sleepForTimeInterval:2.0];
NSLog(@"\n=== NSThread Examples Completed ===");
}
return 0;
}
// Producer thread method
@implementation ProducerConsumer (ProducerThread)
- (void)producerThread {
@autoreleasepool {
for (int i = 0; i < 5; i++) {
NSString *item = [NSString stringWithFormat:@"Product-%d", i];
[self produce:item];
[NSThread sleepForTimeInterval:0.2];
}
}
}
@end
// Consumer thread method
@implementation ProducerConsumer (ConsumerThread)
- (void)consumerThread {
@autoreleasepool {
for (int i = 0; i < 5; i++) {
[self consume];
[NSThread sleepForTimeInterval:0.3];
}
}
}
@endNSOperationQueue
Manage concurrent operations with NSOperationQueue, dependencies, priority levels, and completion blocks
Difficulty
7/10
Estimated time
35 min
Tags
objectivec, macos, multithreading, nsoperation
Prerequisites
Intermediate Objective-C, Foundation framework
// macOS Objective-C NSOperationQueue Examples
// Using Foundation framework
#import <Foundation/Foundation.h>
// MARK: - 1. Basic NSBlockOperation
@interface BlockOperationDemo : NSObject
+ (void)demonstrateBlockOperations;
@end
@implementation BlockOperationDemo
+ (void)demonstrateBlockOperations {
NSLog(@"--- Block Operations ---");
// Create operation queue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 2;
// Create block operations
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Operation 1 started");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Operation 1 completed");
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Operation 2 started");
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Operation 2 completed");
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Operation 3 started");
[NSThread sleepForTimeInterval:0.3];
NSLog(@"Operation 3 completed");
}];
// Add completion blocks
[op3 setCompletionBlock:^{
NSLog(@"Operation 3 completion block executed");
}];
// Add operations to queue
[queue addOperations:@[op1, op2, op3] waitUntilFinished:YES];
NSLog(@"All block operations completed");
}
@end
// MARK: - 2. Custom NSOperation
@interface ImageProcessingOperation : NSOperation
@property (nonatomic, strong) NSString *imageName;
@property (nonatomic, strong) NSString *result;
- (instancetype)initWithImageName:(NSString *)name;
@end
@implementation ImageProcessingOperation {
BOOL _isExecuting;
BOOL _isFinished;
}
- (instancetype)initWithImageName:(NSString *)name {
self = [super init];
if (self) {
_imageName = name;
_isExecuting = NO;
_isFinished = NO;
}
return self;
}
- (BOOL)isAsynchronous {
return YES;
}
- (BOOL)isExecuting {
return _isExecuting;
}
- (BOOL)isFinished {
return _isFinished;
}
- (void)start {
if (self.isCancelled) {
[self willChangeValueForKey:@"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
return;
}
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
// Perform operation on background thread
[self performOperation];
}
- (void)performOperation {
@autoreleasepool {
NSLog(@"Processing image: %@", self.imageName);
// Simulate image processing
[NSThread sleepForTimeInterval:0.5];
self.result = [NSString stringWithFormat:@"Processed_%@", self.imageName];
NSLog(@"Image processed: %@", self.result);
[self completeOperation];
}
}
- (void)completeOperation {
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (void)cancel {
[super cancel];
NSLog(@"Cancelling operation for: %@", self.imageName);
}
@end
// MARK: - 3. Operation Dependencies
@interface DependencyDemo : NSObject
+ (void)demonstrateDependencies;
@end
@implementation DependencyDemo
+ (void)demonstrateDependencies {
NSLog(@"\n--- Operation Dependencies ---");
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
// Create operations
NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Downloading data...");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Download complete");
}];
NSBlockOperation *parseOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Parsing data...");
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Parsing complete");
}];
NSBlockOperation *saveOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Saving data...");
[NSThread sleepForTimeInterval:0.3];
NSLog(@"Save complete");
}];
NSBlockOperation *notifyOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Sending notification...");
[NSThread sleepForTimeInterval:0.2];
NSLog(@"Notification sent");
}];
// Set dependencies
// parse depends on download
[parseOp addDependency:downloadOp];
// save depends on parse
[saveOp addDependency:parseOp];
// notify depends on save
[notifyOp addDependency:saveOp];
NSLog(@"Dependency chain: download -> parse -> save -> notify");
// Add to queue
[queue addOperations:@[notifyOp, saveOp, parseOp, downloadOp] waitUntilFinished:YES];
NSLog(@"All operations completed in correct order");
}
@end
// MARK: - 4. Operation Priority
@interface PriorityDemo : NSObject
+ (void)demonstratePriority;
@end
@implementation PriorityDemo
+ (void)demonstratePriority {
NSLog(@"\n--- Operation Priority ---");
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
// Create operations with different priorities
NSBlockOperation *lowOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Low priority operation executing");
[NSThread sleepForTimeInterval:0.5];
}];
lowOp.queuePriority = NSOperationQueuePriorityLow;
NSBlockOperation *normalOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Normal priority operation executing");
[NSThread sleepForTimeInterval:0.5];
}];
normalOp.queuePriority = NSOperationQueuePriorityNormal;
NSBlockOperation *highOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"High priority operation executing");
[NSThread sleepForTimeInterval:0.5];
}];
highOp.queuePriority = NSOperationQueuePriorityHigh;
// Add in random order
[queue addOperation:normalOp];
[queue addOperation:lowOp];
[queue addOperation:highOp];
[queue waitUntilAllOperationsAreFinished];
NSLog(@"Priority demo completed");
}
@end
// MARK: - 5. Concurrent Operations with Semaphores
@interface ConcurrentDemo : NSObject
+ (void)demonstrateConcurrent;
@end
@implementation ConcurrentDemo
+ (void)demonstrateConcurrent {
NSLog(@"\n--- Concurrent Operations with Limit ---");
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
NSLog(@"Starting 10 operations with max concurrent = 3");
for (NSInteger i = 0; i < 10; i++) {
NSInteger index = i;
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Operation %ld started", (long)index);
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Operation %ld completed", (long)index);
}];
[queue addOperation:op];
}
[queue waitUntilAllOperationsAreFinished];
NSLog(@"All concurrent operations completed");
}
@end
// MARK: - 6. Operation with Progress
@interface ProgressOperation : NSOperation
@property (nonatomic, assign) NSInteger totalSteps;
@property (nonatomic, copy) void (^progressHandler)(double progress);
- (instancetype)initWithTotalSteps:(NSInteger)steps
progressHandler:(void (^)(double))progressHandler;
@end
@implementation ProgressOperation {
BOOL _isExecuting;
BOOL _isFinished;
}
- (instancetype)initWithTotalSteps:(NSInteger)steps
progressHandler:(void (^)(double))progressHandler {
self = [super init];
if (self) {
_totalSteps = steps;
_progressHandler = progressHandler;
_isExecuting = NO;
_isFinished = NO;
}
return self;
}
- (BOOL)isAsynchronous {
return YES;
}
- (BOOL)isExecuting {
return _isExecuting;
}
- (BOOL)isFinished {
return _isFinished;
}
- (void)start {
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
[self performOperation];
}
- (void)performOperation {
for (NSInteger i = 0; i < self.totalSteps && !self.isCancelled; i++) {
[NSThread sleepForTimeInterval:0.2];
double progress = (double)(i + 1) / (double)self.totalSteps;
if (self.progressHandler) {
self.progressHandler(progress);
}
NSLog(@"Progress: %.0f%%", progress * 100);
}
[self completeOperation];
}
- (void)completeOperation {
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
@end
// MARK: - 7. Operation Queue Management
@interface QueueManager : NSObject
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, strong) NSMutableArray<NSOperation *> *activeOperations;
- (instancetype)init;
- (void)addOperation:(NSOperation *)operation;
- (void)cancelAllOperations;
- (void)suspend;
- (void)resume;
@end
@implementation QueueManager
- (instancetype)init {
self = [super init];
if (self) {
_queue = [[NSOperationQueue alloc] init];
_queue.maxConcurrentOperationCount = 4;
_queue.name = @"com.example.queue";
_activeOperations = [NSMutableArray array];
}
return self;
}
- (void)addOperation:(NSOperation *)operation {
[self.activeOperations addObject:operation];
__weak typeof(self) weakSelf = self;
[operation setCompletionBlock:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.activeOperations removeObject:operation];
NSLog(@"Active operations: %lu", (unsigned long)strongSelf.activeOperations.count);
}
}];
[self.queue addOperation:operation];
}
- (void)cancelAllOperations {
NSLog(@"Cancelling %lu operations", (unsigned long)self.activeOperations.count);
for (NSOperation *op in self.activeOperations) {
[op cancel];
}
[self.activeOperations removeAllObjects];
}
- (void)suspend {
[self.queue setSuspended:YES];
NSLog(@"Queue suspended");
}
- (void)resume {
[self.queue setSuspended:NO];
NSLog(@"Queue resumed");
}
@end
// MARK: - Main Demonstration
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"=== macOS Objective-C NSOperationQueue Examples ===\n");
// 1. Block operations
[BlockOperationDemo demonstrateBlockOperations];
// 2. Custom operation
NSLog(@"\n--- Custom Operations ---");
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 2;
NSMutableArray *results = [NSMutableArray array];
for (NSInteger i = 0; i < 5; i++) {
ImageProcessingOperation *op = [[ImageProcessingOperation alloc]
initWithImageName:[NSString stringWithFormat:@"Image%ld", (long)i]];
[op setCompletionBlock:^{
if (op.result) {
@synchronized(results) {
[results addObject:op.result];
}
}
}];
[queue addOperation:op];
}
[queue waitUntilAllOperationsAreFinished];
NSLog(@"Processed images: %@", results);
// 3. Dependencies
[DependencyDemo demonstrateDependencies];
// 4. Priority
[PriorityDemo demonstratePriority];
// 5. Concurrent operations
[ConcurrentDemo demonstrateConcurrent];
// 6. Progress tracking
NSLog(@"\n--- Progress Tracking ---");
ProgressOperation *progressOp = [[ProgressOperation alloc]
initWithTotalSteps:5
progressHandler:^(double progress) {
NSLog(@"Progress callback: %.0f%%", progress * 100);
}];
[progressOp start];
while (progressOp.isExecuting) {
[NSThread sleepForTimeInterval:0.1];
}
// 7. Queue management
NSLog(@"\n--- Queue Management ---");
QueueManager *manager = [[QueueManager alloc] init];
for (NSInteger i = 0; i < 5; i++) {
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Managed operation %ld executing", (long)i);
[NSThread sleepForTimeInterval:0.5];
}];
[manager addOperation:op];
}
[NSThread sleepForTimeInterval:0.3];
[manager suspend];
[NSThread sleepForTimeInterval:0.5];
[manager resume];
[manager.queue waitUntilAllOperationsAreFinished];
NSLog(@"\n=== NSOperationQueue Examples Completed ===");
}
return 0;
}Grand Central Dispatch (GCD)
Use GCD for async operations, dispatch queues, semaphores, groups, and barriers
Difficulty
8/10
Estimated time
40 min
Tags
objectivec, macos, multithreading, gcd
Prerequisites
Intermediate Objective-C, Dispatch framework
// macOS Objective-C Grand Central Dispatch Examples
// Using Foundation and Dispatch framework
#import <Foundation/Foundation.h>
// MARK: - 1. Dispatch Queues
@interface GCDBasics : NSObject
+ (void)demonstrateDispatchQueues;
@end
@implementation GCDBasics
+ (void)demonstrateDispatchQueues {
NSLog(@"--- Dispatch Queues ---");
// Main queue
NSLog(@"Is main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Main queue: Is main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO");
});
// Global queue with different priorities
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
NSLog(@"HIGH priority queue");
});
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
NSLog(@"DEFAULT priority queue");
});
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
NSLog(@"LOW priority queue");
});
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
NSLog(@"BACKGROUND priority queue");
});
// Custom queue
dispatch_queue_t customQueue = dispatch_queue_create("com.example.custom", DISPATCH_QUEUE_SERIAL);
dispatch_async(customQueue, ^{
NSLog(@"Custom serial queue - Task 1");
});
dispatch_async(customQueue, ^{
NSLog(@"Custom serial queue - Task 2");
});
[NSThread sleepForTimeInterval:1.0];
}
@end
// MARK: - 2. Dispatch Sync vs Async
@interface SyncAsyncDemo : NSObject
+ (void)demonstrateSyncAsync;
@end
@implementation SyncAsyncDemo
+ (void)demonstrateSyncAsync {
NSLog(@"\n--- Sync vs Async ---");
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
NSLog(@"Before async dispatch");
dispatch_async(queue, ^{
NSLog(@"Async task started");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Async task completed");
});
NSLog(@"After async dispatch (immediate)");
NSLog(@"\nBefore sync dispatch");
dispatch_sync(queue, ^{
NSLog(@"Sync task started");
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Sync task completed");
});
NSLog(@"After sync dispatch (waited)");
}
@end
// MARK: - 3. Dispatch After
@interface DelayDemo : NSObject
+ (void)demonstrateDelay;
@end
@implementation DelayDemo
+ (void)demonstrateDelay {
NSLog(@"\n--- Dispatch After ---");
NSLog(@"Scheduling delayed task...");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
NSLog(@"Delayed task executed after 2 seconds");
});
NSLog(@"Task scheduled, continuing...");
[NSThread sleepForTimeInterval:2.5];
}
@end
// MARK: - 4. Dispatch Groups
@interface GroupDemo : NSObject
+ (void)demonstrateGroups;
@end
@implementation GroupDemo
+ (void)demonstrateGroups {
NSLog(@"\n--- Dispatch Groups ---");
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
// Enter group manually
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Task 1 started");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Task 1 completed");
dispatch_group_leave(group);
});
// Add to group automatically
dispatch_group_async(group, queue, ^{
NSLog(@"Task 2 started");
[NSThread sleepForTimeInterval:0.8];
NSLog(@"Task 2 completed");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 3 started");
[NSThread sleepForTimeInterval:0.5]);
NSLog(@"Task 3 completed");
});
// Wait for all tasks
NSLog(@"Waiting for group...");
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"All group tasks completed");
// Notify when complete
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Group notify callback: All tasks done!");
});
[NSThread sleepForTimeInterval:0.5];
}
@end
// MARK: - 5. Dispatch Semaphores
@interface SemaphoreDemo : NSObject
+ (void)demonstrateSemaphores;
@end
@implementation SemaphoreDemo
+ (void)demonstrateSemaphores {
NSLog(@"\n--- Dispatch Semaphores ---");
// Create semaphore with initial value
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
NSLog(@"Starting 10 tasks with semaphore (limit 3)");
for (NSInteger i = 0; i < 10; i++) {
dispatch_async(queue, ^{
// Wait for semaphore
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Task %ld started", (long)i);
// Simulate work
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Task %ld completed", (long)i);
// Signal semaphore
dispatch_semaphore_signal(semaphore);
});
}
[NSThread sleepForTimeInterval:3.0);
// Semaphore as mutex
NSLog(@"\nSemaphore as mutex:");
dispatch_semaphore_t mutex = dispatch_semaphore_create(1);
__block NSInteger counter = 0;
for (NSInteger i = 0; i < 5; i++) {
dispatch_async(queue, ^{
dispatch_semaphore_wait(mutex, DISPATCH_TIME_FOREVER);
NSInteger value = counter++;
NSLog(@"Thread %ld read counter: %ld", (long)i, (long)value);
dispatch_semaphore_signal(mutex);
});
}
[NSThread sleepForTimeInterval:1.0];
}
@end
// MARK: - 6. Dispatch Barriers
@interface BarrierDemo : NSObject
+ (void)demonstrateBarriers;
@end
@implementation BarrierDemo
+ (void)demonstrateBarriers {
NSLog(@"\n--- Dispatch Barriers ---");
// Create concurrent queue
dispatch_queue_t queue = dispatch_queue_create("com.example.concurrent",
DISPATCH_QUEUE_CONCURRENT);
NSMutableArray *dataArray = [NSMutableArray array];
// Read operations (concurrent)
for (NSInteger i = 0; i < 3; i++) {
dispatch_async(queue, ^{
NSLog(@"Read %lu: %@", (unsigned long)i, dataArray);
});
}
// Write operation (barrier - exclusive)
dispatch_barrier_async(queue, ^{
NSLog(@"Barrier: Writing data");
[dataArray addObject:@"Item 1"];
[dataArray addObject:@"Item 2"];
[NSThread sleepForTimeInterval:0.5];
NSLog(@"Barrier: Write complete");
});
// Read operations (concurrent)
for (NSInteger i = 0; i < 3; i++) {
dispatch_async(queue, ^{
NSLog(@"Read %lu: %@", (unsigned long)(i + 3), dataArray);
});
}
// Sync barrier
dispatch_barrier_sync(queue, ^{
NSLog(@"Sync barrier: Clearing data");
[dataArray removeAllObjects];
});
NSLog(@"Data after sync barrier: %@", dataArray);
[NSThread sleepForTimeInterval:1.0];
}
@end
// MARK: - 7. Dispatch Apply
@interface ApplyDemo : NSObject
+ (void)demonstrateApply;
@end
@implementation ApplyDemo
+ (void)demonstrateApply {
NSLog(@"\n--- Dispatch Apply ---");
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
NSLog(@"Processing array with dispatch_apply");
NSArray *data = @[@"Item1", @"Item2", @"Item3", @"Item4", @"Item5"];
dispatch_apply(data.count, queue, ^(size_t index) {
NSString *item = data[index];
NSLog(@"Processing %@ (index: %lu)", item, (unsigned long)index);
[NSThread sleepForTimeInterval:0.2];
});
NSLog(@"All items processed (dispatch_apply blocks until done)");
}
@end
// MARK: - 8. Dispatch Once
@interface OnceDemo : NSObject
+ (void)demonstrateOnce;
@end
@implementation OnceDemo {
static dispatch_once_t onceToken;
static NSString *sharedInstance;
}
+ (void)demonstrateOnce {
NSLog(@"\n--- Dispatch Once ---");
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
for (NSInteger i = 0; i < 5; i++) {
dispatch_async(queue, ^{
dispatch_once(&onceToken, ^{
NSLog(@"Dispatch once executed (should see this only once)");
sharedInstance = @"Singleton Instance";
});
NSLog(@"Iteration %ld, shared instance: %@", (long)i, sharedInstance);
});
}
[NSThread sleepForTimeInterval:1.0];
}
@end
// MARK: - 9. Dispatch I/O
@interface IODemo : NSObject
+ (void)demonstrateIO;
@end
@implementation IODemo
+ (void)demonstrateIO {
NSLog(@"\n--- Dispatch I/O ---");
dispatch_queue_t ioQueue = dispatch_queue_create("com.example.io",
DISPATCH_QUEUE_SERIAL);
dispatch_async(ioQueue, ^{
NSLog(@"Simulating file read...");
[NSThread sleepForTimeInterval:0.5];
NSLog(@"File read complete");
// Process on default queue
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
NSLog(@"Processing data...");
[NSThread sleepForTimeInterval:0.3];
// Write back on I/O queue
dispatch_async(ioQueue, ^{
NSLog(@"Simulating file write...");
[NSThread sleepForTimeInterval:0.5];
NSLog(@"File write complete");
});
});
});
[NSThread sleepForTimeInterval:2.0];
}
@end
// MARK: - 10. Dispatch Source (Timer)
@interface SourceDemo : NSObject
+ (void)demonstrateSource;
@end
@implementation SourceDemo
+ (void)demonstrateSource {
NSLog(@"\n--- Dispatch Source (Timer) ---");
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
__block NSInteger counter = 0;
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0,
0,
queue);
dispatch_source_set_timer(timer,
dispatch_time(DISPATCH_TIME_NOW, 0),
500 * NSEC_PER_MSEC, // 500ms
100 * NSEC_PER_MSEC); // 100ms leeway
dispatch_source_set_event_handler(timer, ^{
counter++;
NSLog(@"Timer tick %ld", (long)counter);
if (counter >= 5) {
dispatch_source_cancel(timer);
NSLog(@"Timer cancelled");
}
});
dispatch_resume(timer);
// Wait for timer to complete
[NSThread sleepForTimeInterval:3.0];
}
@end
// MARK: - Main Demonstration
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"=== macOS Objective-C Grand Central Dispatch Examples ===\n");
// 1. Basic queues
[GCDBasics demonstrateDispatchQueues];
// 2. Sync vs async
[SyncAsyncDemo demonstrateSyncAsync];
// 3. Delay
[DelayDemo demonstrateDelay];
// 4. Groups
[GroupDemo demonstrateGroups];
// 5. Semaphores
[SemaphoreDemo demonstrateSemaphores];
// 6. Barriers
[BarrierDemo demonstrateBarriers];
// 7. Apply
[ApplyDemo demonstrateApply];
// 8. Once
[OnceDemo demonstrateOnce];
// 9. I/O
[IODemo demonstrateIO];
// 10. Source
[SourceDemo demonstrateSource];
NSLog(@"\n=== GCD Examples Completed ===");
}
return 0;
}Tools
Tools frequently paired with this sample
Related