I am asking because the I was dabbling into some complicated block code and I did not expect the following code to work properly.
Say we have a BOOL property, as so:
@property (nonatomic, assign) BOOL isCancelled;
It's auto synthesised, no custom getter, no setter, no explicit ivar.
Then, there's this code... which works perfectly
dispatch_async(queue, ^{
id result = block(&_isCancelled);
if (!_isCancelled) { ... }
}
However, I would have expected it work for the block() call, but not for the if, where I thought it would capture the value of _isCancelled and keep it const, not have it mutate throughout execution. Still, at runtime, the value of _isCancelled is always consistent inside/outside the block, as if it were actually BOOL *
Can anyone explain what's going on?
When declaring a property BOOL cancelled
the autosynthesized ivar is BOOL _isCancelled
. This is a primitive variable, not a pointer.
However, when a block is capturing ivars, it is actually capturing self
, not the ivar itself. Reading ivar _isCancelled
actually means reading self->_isCancelled
.
Therefore, ivars are not captured by value unless you save them into a local variable first (e.g. BOOL isCancelled = _isCancelled
).
See Block automatic retaining, does it affect even to ivars in self? for more information.