What happens if I send a message to a weak object? Does sending the message possess the object and hold it in memory until return?
I'm thinking of this pattern:
__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomeAction];
});
Assuming weakSelf
is non-nil when the message is sent, might it be deallocated while doSomeAction
is working or is it guaranteed to remain valid until doSomeAction
returns?
From the Clang ARC documentation:
Messaging a weak reference performs an lvalue-to-rvalue conversion on the variable, which means the value of the weak reference will be retained and then released at the end of the current full-expression (basically, the statement). It's basically equivalent to assigning to a strong variable whose scope only lasts for the current statement, and then messaging that strong variable.
The takeaway here is if you want to message a weak variable once, and never touch it again, and you don't care about the side-effects of evaluating the arguments to the method in the case where the weak reference ends up
nil
, then go ahead and message the weak reference directly. But if you need to refer to the weak reference twice (in separate statements), or the side-effects of evaluating the arguments do matter, then you should assign to a strong variable and test for non-nil
before proceeding.You asked:
Yes, not only does it remain valid until
doSomeAction
returns, it is retained for the rest of the block, too. Consider the following:In this example, I make sure that the object was in scope when the block starts, but let it fall out of scope between
doSomeAction
anddoSomeAction2
, but the block appears to retain it for the completion of the block. But if I comment out the invocation ofdoSomeAction
, theweak
reference isnil
by the time it gets todoSomeAction2
, just as you'd expect.As an aside, in WWDC 2011 - #322 - Objective-C Advancements In-Depth, they point out (about 27:00 min into the video), they point out that if you're dereferencing
weakSelf
, you should have a local strong reference inside the dispatch block to protect yourself in race condition, thus:That will retain it for the duration of the block (assuming it wasn't already deallocated by the time the block was executed).