Exemplos de Multithreading macOS Objective-C

Exemplos de multithreading macOS Objective-C incluindo NSThread, NSOperationQueue, Grand Central Dispatch e primitivas de sincronização

💻 Conceitos Básicos de NSThread objectivec

🟢 simple ⭐⭐⭐

Criar e gerenciar threads usando NSThread com separação, inicialização e sincronização

⏱️ 25 min 🏷️ 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];
        }
    }
}
@end

💻 NSOperationQueue objectivec

🟡 intermediate ⭐⭐⭐⭐

Gerenciar operações concorrentes com NSOperationQueue, dependências, níveis de prioridade e blocos de conclusão

⏱️ 35 min 🏷️ 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) objectivec

🟡 intermediate ⭐⭐⭐⭐

Usar GCD para operações assíncronas, filas de despacho, semáforos, grupos e barreiras

⏱️ 40 min 🏷️ 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(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"HIGH priority queue");
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"DEFAULT priority queue");
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        NSLog(@"LOW priority queue");
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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(DISPATCH_QUEUE_PRIORITY_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;
}