Do I need to check if weak self is nil in blocks?
I create weakSelf pointer like:
__weak typeof(self) weakSelf = self;
and in the beginning of the blocks I do
if(!weakSelf){return;}
is this unnecessary? or does it depend on whether I coded the rest correctly so that when the self dies, others die too?
That check is unnecessary, and is giving you a false sense of security.
Here's the problem:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf) { return; }
// THE LINE OF INTEREST
[weakSelf doSomething];
});
At THE LINE OF INTEREST
, some other thread might clear the last strong reference to self
, at which point weakSelf
is set to nil. So the doSomething
message gets sent to nil, which is “safe” (it does nothing), but might not be what you expected!
It's worse if you want to take a different action when weakSelf
is nil, e.g.
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf) {
[weakSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});
In this case, between the time the block verifies that weakSelf
is not nil and the time it sends the doSomething
message, weakSelf
might become nil, and neither doSomething
nor doSomethingElse
will actually run.
The correct solution is this:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});
In this case, copying weakSelf
to strongSelf
(which is strong by default) is atomic. If weakSelf
was nil, strongSelf
will be nil. If weakSelf
was not nil, strongSelf
will not be nil, and will be a strong reference to the object, preventing it from being deallocated before the doSomething
message.