According to the Clang docs, "For __weak objects, the current pointee is retained and then released at the end of the current full-expression." Which to me indicates that if I do this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
[weakSelf doSomethingInBlock];
}
}];
NOTE
If you reference @dasblinkenlight's answer below, you'll notice that there is a possibility of weakSelf
becoming nil
before doSomethingBlock
.
Assuming doSomethingInBlock
, does start with weakSelf
existing, the rest of it should run no problem and there's no risk of weakSelf
becoming nil
before it has finished executing. However, if I were to run this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
// Guaranteed to be retained for scope of expression
[weakSelf doSomethingInBlock];
// weakSelf could possibly be nil before reaching this point
[weakSelf doSomethingElseInBlock];
}
}];
The work around that is suggested is to take weakSelf
and convert it to a strong variable inside of the block, like this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomethingInBlock];
[strongSelf doSomethingElseInBlock];
}
}];
What happens to the weakSelf
and strongSelf
during multiple iterations of the same block? Is there a chance that in processBlock()
(below), self could exist for some objects and not for others?
For example, if I were processing an array of objects in the background using something like this, where processBlock
contains references to self:
- (void) processValuesInBackgroundWithArray:(NSArray *)array usingBlock:(void (^)(id))processBlock {
for (id ob in array) {
// Block is called for each Object
// Is there a chance that self will exist for some objects and not for others?
processBlock(ob);
}
}
Called like this:
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
So the block references strongSelf
from weakSelf
, but the block is executed multiple times. Is there a chance that strongSelf
might become nil
in between iterations of objects in an array?
There is no guarantee that in your first example the weakSelf
inside the if
would be non-nil
, because the block has two full expressions that reference it:
if (weakSelf)
check is the first full expressionweakSelf
in [weakSelf doSomethingInBlock];
invocation is the second one.Therefore, your trick with strongSelf
should be applied even when there is only one weakSelf
invocation "protected" by the if
statement.
Is there a chance that in processBlock()(below), self could exist for some objects and not for others?
Since there is no guaranteed __strong
reference in a stack frame preceding the processValuesInBackgroundWithArray:
call, self
may become released between iterations of the loop, but only in a situation when the call of your last code snippet happens on a __weak
or an unretained reference to the object containing the method from your last snippet.
Let's say that your last code snippet is inside a method called testWeak
, in a class called MyClass
:
-(void)testWeak {
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
}
When the call is made like this
[myClassObj testWeak];
and myClassObj
is __strong
, the self
object inside testWeak
would be retained outside the call by the strong reference to myClassObj
, so your code would be good, with or without the strongSelf
trick.
When myClassObj
is weak, however, and the last __strong
reference gets released concurrently with the running loop, some objects inside the loop would end up seeing a nil
weakSelf
inside the block. The only difference that the strongSelf
is going to make is preventing that doSomethingElseWithObject
would be called on nil
, while doSomethingWithObject
would be called on a non-nil
object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With