In the code below, self is retained to assure that the image object lives when the block gets called. That's what the docs say. However, I don't seem to understand why. Simply retaining the image would have guarantee that it doesn't get deallocated. So why retain self as well?
self.finishBlock = ^{
self.image.hidden = YES;
}
Does this apply if you access the image directly?
self.finishBlock = ^{
_image.hidden = YES;
}
self is retained because
self.image.hidden = YES;
is actually
[[self image] setHidden:YES];
The image isn't/can't be retained directly because it's not available until the block is executed and [self image]
is called to obtain the image.
Your second example also retains self, though for a slightly different reason. In Objective-C, when you access an instance variable directly, it's actually accessed via self's underlying struct. So, _image
is actually self->_image
after compilation. Again, the block needs access to self, so it retains self.
Also worth noting is that in either case, if the value of _image changes before the block is executed, the block will "see" the new value. That is often, but not always what you want.
You have two options to avoid retaining self. The first will do so and will capture the value of _image at the time the block is defined, so even if it changes, the block will see the original value. This approach is to define a local variable, set it to the current value returned by self.image
, then use that in the block:
UIImage *image = self.image;
self.finishBlock = ^{
image.hidden = YES;
}
The other approach is to capture a weak version of self and use that in the block. In this case, the block will have a weak -- instead of strong -- reference to self (ie. won't retain self). However, the -image
accessor method on self will still be called, so if image is changed before the block runs, the new value will be used:
__weak YourClass *weakSelf = self;
self.finishBlock = ^{
weakSelf.image.hidden = YES;
}
Note that in this case, if self
is deallocated before the block runs, weakSelf
will be nil, and the statement in the block will effectively be a NOOP (message sends to nil don't do anything in Objective-C).
A block needs to retain any captured objects in the block. Your first block example is really:
self.finishBlock = ^{
[[self image] setHidden:YES];
}
The block must retain self
so it can properly call the image
method. As written the block can't simply retain image
because the image isn't obtained until the block is executed and the image
method is called. So the only option here is to retain self
.
In the second block you really have:
self.finishBlock = ^{
self->_image.hidden = YES;
}
so again, self
must be retained so the proper value of the _image
ivar is accessed when the block is actually executed.
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