Why is it stored in a block that refers to one of its properties?

In the code below, self is saved to ensure that the image object will live when the block is called. This is what the documents say. However, it seems I do not understand why. Simply storing the image would ensure that it would not be freed. So why save yourself?

self.finishBlock = ^{ self.image.hidden = YES; } 

Does this apply if you directly access the image?

 self.finishBlock = ^{ _image.hidden = YES; } 
+4
source share
2 answers

The block needs to save any captured objects in the block. An example of your first block:

 self.finishBlock = ^{ [[self image] setHidden:YES]; } 

The block must save self so that it can correctly call the image method. As recorded, the block cannot simply save the image , because the image will not be received until the block is executed and the image method is called. So the only option is to keep self .

In the second block, you really have:

 self.finishBlock = ^{ self->_image.hidden = YES; } 

so self must be kept in order to get the correct _image ivar when the block is actually executed.

+3
source

self is saved because

 self.image.hidden = YES; 

actually

 [[self image] setHidden:YES]; 

The image is not saved / cannot be saved directly, because it is not available until the block is executed, and [self image] is called to obtain the image.

The second example also preserves itself, although for a different reason. In Objective-C, when you access an instance variable directly, it is actually accessed through its own underlying structure. So, _image is actually self->_image after compilation. Again, the block needs access to itself, so it saves itself.

It is also worth noting that in any case, if the _image value is changed before the block is executed, the block will "see" the new value. This is often, but not always, what you want.

You have two options to avoid saving yourself. The first one will do this and fix the _image value at the moment 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 , and then use this in a block:

 UIImage *image = self.image; self.finishBlock = ^{ image.hidden = YES; } 

Another approach is to commit a weak version of self and use it in a block. In this case, the block will have a weak - instead of a strong - link to itself (i.e., it will not save itself). However, the -image accessor on self method will still be called, so if the image is changed before the block starts, the new value will be used:

 __weak YourClass *weakSelf = self; self.finishBlock = ^{ weakSelf.image.hidden = YES; } 

Note that in this case, if self freed before the block is started, weakSelf will be zero, and the statement in the block will effectively be NOOP (message sends to nil to do nothing in Objective-C).

+7
source

All Articles