为什么self保留在访问其中一个属性的块中?

时间:2013-01-28 16:40:25

标签: iphone ios objective-c ipad automatic-ref-counting

在下面的代码中,self被保留以确保在调用块时图像对象存在。这就是文档所说的。但是,我似乎不明白为什么。简单地保留图像可以保证它不会被解除分配。那么为什么还要保留自己呢?

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

如果直接访问图像,这是否适用?

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

2 个答案:

答案 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;
}

请注意,在这种情况下,如果在块运行之前释放selfweakSelf将为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的正确值。