Proper way to force object to live until block will be executed

Viewed 136

I am using automatic reference counting. And I want object to live until some callback will be executed:

 Foo *obj = [[Foo alloc] init];
 [obj someMethod: @"AAA", ^(NSError * _Nullable error) {
    //callback
  });

I need obj to be alive until "callback" will be called, but I don't actually use it in callback. For now I "solve" it with:

[obj someMethod: @"AAA", ^(NSError * _Nullable error) {
    //callback
    NSLog(@"To make sure that obj alive print it: %@", obj);
  });

But this looks weird. May be there is some language construction for such case, or there is some typical workaround for this except printing to log?

2 Answers

If you use the outer variable obj inside the block, then its value is captured into the block. This creates an additional reference to the object, so that automatic reference counting keeps it alive until the block has executed.

To keep that reference, you don't need to pass it to another function, like NSLog(). It's sufficient to just store it in a local variable.

Foo *obj = [[Foo alloc] init];
[obj someMethod: @"AAA", ^(NSError * _Nullable error) {
    Foo* keepObj = obj; // keeps obj alive
    //callback
});

Edit: improved solution after feedback from skaak: the unused local variable name is not needed, and you can signal the intention with a cast to void.

Foo *obj = [[Foo alloc] init];
[obj someMethod: @"AAA", ^(NSError * _Nullable error) {
    //callback
    (void) obj; // release reference that kept obj alive
});

To manually manage a life cycle of your object you can capture it by setting nil inside the block e.g.:

__block Foo *obj = [Foo new];
[obj someMethod:@"AAA" block:^(NSError * _Nullable error) {
    NSLog(@"start block");
    
    ...
    
    obj = nil;
    NSLog(@"end block");
}];

NSLog(@"finish");


Prints:

start block
Foo dealloc
end block
finish
Related