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?
When you use
__unsafe_unretained
, then the reference remains around even after the object is deallocated. So if the view controller gets popped, thenweakSelf
is now pointing to a deallocated object.If you change it to
__weak
instead, then when the view controller gets deallocated, it will setweakSelf
tonil
, and you'll be fine. You don't even need to do a check for ifweakSelf
is set to anything, because calling a method onnil
has no effect.