在下面的代码中,self被保留以确保在调用块时图像对象存在。这就是文档所说的。但是,我似乎不明白为什么。简单地保留图像可以保证它不会被解除分配。那么为什么还要保留自己呢?
self.finishBlock = ^{
self.image.hidden = YES;
}
如果直接访问图像,这是否适用?
self.finishBlock = ^{
_image.hidden = YES;
}
答案 0 :(得分:7)
自我被保留,因为
self.image.hidden = YES;
实际上是
[[self image] setHidden:YES];
图像不能/不能直接保留,因为在执行块并且调用[self image]
来获取图像之前它不可用。
你的第二个例子也保留了自我,但原因略有不同。在Objective-C中,当您直接访问实例变量时,它实际上是通过self的底层结构访问的。因此,编译后_image
实际上是self->_image
。同样,该块需要访问self,因此它保留了self。
另外值得注意的是,在任何一种情况下,如果_image的值在执行块之前发生变化,则块将“看到”新值。这通常是,但并不总是你想要的。
您有两种选择可以避免自我保留。第一个将这样做和将在定义块时捕获_image的值,因此即使它发生更改,块也会看到原始值。这种方法是定义一个局部变量,将其设置为self.image
返回的当前值,然后在块中使用它:
UIImage *image = self.image;
self.finishBlock = ^{
image.hidden = YES;
}
另一种方法是捕获弱版本的self并在块中使用它。在这种情况下,块将具有弱 - 而不是强 - 对自我的引用(即,不会保留自己)。但是,仍将调用self上的-image
访问器方法,因此如果在块运行之前更改了图像,则将使用新值:
__weak YourClass *weakSelf = self;
self.finishBlock = ^{
weakSelf.image.hidden = YES;
}
请注意,在这种情况下,如果在块运行之前释放self
,weakSelf
将为nil,并且块中的语句将实际上是NOOP(消息发送到nil不在Objective-C中做任何事情。
答案 1 :(得分:3)
块需要保留块中的任何捕获对象。你的第一个例子就是:
self.finishBlock = ^{
[[self image] setHidden:YES];
}
该块必须保留self
,以便正确调用image
方法。如上所述,块不能简单地保留image
,因为在块执行并调用image
方法之前不会获得图像。因此,此处唯一的选择是保留self
。
在第二个区块中你真的有:
self.finishBlock = ^{
self->_image.hidden = YES;
}
所以,必须保留self
,以便在实际执行块时访问_image
ivar的正确值。