Waitgroups in Objective-C

Our first example demonstrates the use of a dispatch group, which is similar to a wait group. It allows us to wait for multiple asynchronous tasks to finish.

#import <Foundation/Foundation.h>

// This is the function we'll run in every dispatch queue.
void worker(int id) {
    NSLog(@"Worker %d starting", id);
    
    // Sleep to simulate an expensive task.
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"Worker %d done", id);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // This dispatch group is used to wait for all the
        // dispatch queues launched here to finish.
        dispatch_group_t group = dispatch_group_create();
        
        // Launch several dispatch queues and add them to the dispatch group.
        for (int i = 1; i <= 5; i++) {
            dispatch_group_enter(group);
            
            // Wrap the worker call in a block that makes sure to tell
            // the dispatch group that this worker is done. This way the worker
            // itself does not have to be aware of the concurrency primitives
            // involved in its execution.
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                worker(i);
                dispatch_group_leave(group);
            });
        }
        
        // Block until all tasks in the dispatch group are done.
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        
        // Note that this approach has no straightforward way
        // to propagate errors from workers. For more
        // advanced use cases, consider using NSOperation and NSOperationQueue.
    }
    return 0;
}

To run the program, compile it and then execute:

$ clang -framework Foundation waitgroups.m -o waitgroups
$ ./waitgroups
Worker 3 starting
Worker 1 starting
Worker 2 starting
Worker 4 starting
Worker 5 starting
Worker 3 done
Worker 1 done
Worker 2 done
Worker 4 done
Worker 5 done

The order of workers starting up and finishing is likely to be different for each invocation.

In this Objective-C version, we use Grand Central Dispatch (GCD) which is the native concurrency framework for iOS and macOS. The dispatch_group_t is analogous to the WaitGroup in Go. We use dispatch_group_enter and dispatch_group_leave to increment and decrement the group’s counter, respectively. The dispatch_group_wait function blocks until all tasks in the group are complete, similar to WaitGroup.Wait() in Go.

Note that Objective-C and the iOS/macOS ecosystem don’t have a direct equivalent to goroutines. Instead, we use GCD’s dispatch queues to perform concurrent operations. This approach provides similar functionality but with a different API and underlying implementation.