Timeouts in Objective-C

Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Objective-C is possible using Grand Central Dispatch (GCD) and blocks.

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        // For our example, suppose we're executing an external
        // call that returns its result on a dispatch_semaphore_t after 2s.
        dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(0);
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2.0];
            NSLog(@"result 1");
            dispatch_semaphore_signal(semaphore1);
        });
        
        // Here's the implementation of a timeout.
        // We'll use dispatch_semaphore_wait with a timeout to achieve this.
        dispatch_time_t timeout1 = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
        if (dispatch_semaphore_wait(semaphore1, timeout1) == 0) {
            NSLog(@"Received result 1");
        } else {
            NSLog(@"timeout 1");
        }
        
        // If we allow a longer timeout of 3s, then the wait
        // for semaphore2 will succeed and we'll print the result.
        dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
        dispatch_async(queue, ^{
            [NSThread sleepForTimeInterval:2.0];
            NSLog(@"result 2");
            dispatch_semaphore_signal(semaphore2);
        });
        
        dispatch_time_t timeout2 = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
        if (dispatch_semaphore_wait(semaphore2, timeout2) == 0) {
            NSLog(@"Received result 2");
        } else {
            NSLog(@"timeout 2");
        }
    }
    return 0;
}

Running this program shows the first operation timing out and the second succeeding.

$ clang main.m -framework Foundation -o timeouts && ./timeouts
timeout 1
result 1
result 2
Received result 2

In this Objective-C version:

  1. We use Grand Central Dispatch (GCD) for concurrency instead of goroutines.
  2. dispatch_semaphore_t is used to signal when an operation is complete, similar to channels in the original example.
  3. dispatch_semaphore_wait with a timeout is used to implement the timeout functionality, replacing the select statement with time.After.
  4. NSLog is used for printing output instead of fmt.Println.
  5. The @autoreleasepool block is used to manage memory automatically.

While the structure is different due to language differences, the core concept of implementing timeouts remains the same.