4

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

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

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

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

2 回答 2

7

自我保留,因为

self.image.hidden = YES;

实际上是

[[self image] setHidden:YES];

图像不能/不能直接保留,因为在执行块并[self image]调用以获取图像之前它不可用。

您的第二个示例也保留了 self ,尽管原因略有不同。在 Objective-C 中,当你直接访问一个实例变量时,它实际上是通过 self 的底层结构访问的。所以,_image其实是self->_image经过编译的。同样,该块需要访问自我,因此它保留自我。

另外值得注意的是,在任何一种情况下,如果 _image 的值在块执行之前发生变化,块将“看到”新值。这通常是你想要的,但并不总是你想要的。

您有两种选择来避免保留自我。第一个会这样做,会在定义块时捕获 _image 的值,因此即使它发生变化,块也会看到原始值。这种方法是定义一个局部变量,将其设置为返回的当前值self.image,然后在块中使用它:

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

另一种方法是捕获 self 的弱版本并在块中使用它。在这种情况下,块将有一个弱的——而不是强的——对 self 的引用(即不会保留 self)。但是,-imageself 上的访问器方法仍然会被调用,因此如果在块运行之前更改了图像,则将使用新值:

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

请注意,在这种情况下,如果self在块运行之前释放,weakSelf将为 nil,并且块中的语句将有效地成为 NOOP(发送到 nil 的消息在 Objective-C 中不做任何事情)。

于 2013-01-28T16:50:32.520 回答
3

块需要在块中保留任何捕获的对象。您的第一个块示例实际上是:

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

该块必须保留self,以便它可以正确调用该image方法。正如所写的那样,该块不能简单地保留image,因为直到执行该块并image调用该方法才获得图像。所以这里唯一的选择是保留self.

在第二个区块中,您确实拥有:

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

所以同样,self必须保留,以便在_image实际执行块时访问 ivar 的正确值。

于 2013-01-28T16:54:44.423 回答