Defer in Objective-C

In Objective-C, there isn’t a direct equivalent to the defer keyword. However, we can achieve similar functionality using the @finally block in a try-catch-finally statement. Here’s how we can implement the same concept:

#import <Foundation/Foundation.h>

@interface FileManager : NSObject

+ (NSFileHandle *)createFile:(NSString *)path;
+ (void)writeToFile:(NSFileHandle *)file;
+ (void)closeFile:(NSFileHandle *)file;

@end

@implementation FileManager

+ (NSFileHandle *)createFile:(NSString *)path {
    NSLog(@"creating");
    return [NSFileHandle fileHandleForWritingAtPath:path];
}

+ (void)writeToFile:(NSFileHandle *)file {
    NSLog(@"writing");
    [file writeData:[@"data\n" dataUsingEncoding:NSUTF8StringEncoding]];
}

+ (void)closeFile:(NSFileHandle *)file {
    NSLog(@"closing");
    [file closeFile];
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSFileHandle *file = nil;
        @try {
            file = [FileManager createFile:@"/tmp/defer.txt"];
            [FileManager writeToFile:file];
        }
        @finally {
            if (file) {
                [FileManager closeFile:file];
            }
        }
    }
    return 0;
}

In this Objective-C version:

  1. We define a FileManager class with class methods for creating, writing to, and closing files.

  2. In the main function, we use a try-finally block to ensure that the file is closed after we’re done with it, similar to how defer works in the original example.

  3. The @finally block will always execute, regardless of whether an exception is thrown or not, ensuring that our cleanup code (closing the file) always runs.

  4. We check if the file is non-nil before closing it in the @finally block to avoid potential issues.

  5. Error handling is done through Objective-C’s exception mechanism. If an error occurs during file operations, an NSException will be thrown.

To run the program:

$ clang -framework Foundation defer.m -o defer
$ ./defer
creating
writing
closing

This approach ensures that the file is closed after being written, mimicking the behavior of the defer keyword in the original example.

It’s important to note that while this achieves a similar result, the @finally block in Objective-C is not exactly the same as defer. The @finally block is tied to a specific scope and exception handling, whereas defer in Go is more flexible and can be used outside of exception handling contexts.