Search code examples
iosautomatic-ref-countingnszombie

Zombie when calling completion block in background thread


I pass a completion block to my method, this completion block will be called in the background when a network request is finished. Unfortunately, if the calling object is deallocated in the meantime, the app crashes:

ViewController (which may be deallocated because it's popped from the navigation stack) code:

__unsafe_unretained ViewController *weakSelf = self;

[[URLRequester instance] sendUrl:url successBlock:^(id JSON) {
    [weakSelf webserviceCallReturned:JSON];
}];

URLRequester-Code (made simpler, of course):

- (void)sendUrl:(NSString *)urlAfterHost successBlock:(void (^)(id))successBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(2);
        successBlock(nil);
        return;
    });
}

If, in this 2 seconds, the ViewController gets popped from the navigation stack, the app crashes. What am I missing?


Solution

  • When you use __unsafe_unretained, then the reference remains around even after the object is deallocated. So if the view controller gets popped, then weakSelf is now pointing to a deallocated object.

    If you change it to __weak instead, then when the view controller gets deallocated, it will set weakSelf to nil, and you'll be fine. You don't even need to do a check for if weakSelf is set to anything, because calling a method on nil has no effect.