You cannot dereference ivars with ->
if this
is nil
. So, the typical solution is to create strong reference that can’t be deallocated while the closure runs, and return
if it’s nil
:
- (NSString * _Nullable)process {
typeof(self) __weak weakSelf = self;
[self asynchronousMethodWithCompletion:^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
// can now safely use `strongSelf` here
});
...
}
This is “weakSelf
-strongSelf
dance”. You use it in situations where you need to make sure that self
isn’t nil
when you use it, e.g. dereferencing ivars (strongSelf->ivar
) .
Thus:
- (NSString * _Nullable)process {
typeof(self) __weak weakSelf = self;
NSString __block *ret = nil;
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(_repQueue, ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
[strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
ret = [some op .. ];
dispatch_group_leave(group);
}];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
info(@"%@", @"done");
return ret;
}
A few other observations:
The dispatch group should be a local variable of the method rather than an ivar. There’s no need for anything else in your code referencing this group
.
Make sure that your dispatch_group_leave
calls don’t exceed the number of dispatch_group_enter
calls (i.e. that this completion handler block isn’t called multiple times).
I’d suggest waiting for DISPATCH_TIME_FOREVER
(assuming you want it to really wait for it to finish).
Also, if these are properties (which I’m guessing they are on the basis of the underscores), then using self.env
rather than self->_env
is safer, as it won’t crash if self
is nil
, but rather will just return nil
.
I must confess that this still doesn’t look right (e.g. if updateFromTable
is asynchronous already, why bother dispatching this asynchronously to _repQueue
; if it is synchronous, then again, why dispatch this asynchronously only to wait for it). But it’s impossible to comment further without seeing the updateFromTable
implementation.
Or, better, make the method asynchronous:
- (void)processWithCompletion:(void (^)(NSString *))callback {
typeof(self) __weak weakSelf = self;
dispatch_async(_repQueue, ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
[strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
NSString *ret = [some op .. ];
callback(ret);
}];
});
}