为什么在访问自身属性的块中要使用self关键字?

4
在下面的代码中,保留self是为了确保图像对象在调用块时仍然存在。这就是文档所说的。然而,我似乎不明白为什么要这样做。仅仅保留图像就可以保证它不会被释放。那么为什么还要保留self呢?
self.finishBlock = ^{
    self.image.hidden = YES;
}

如果您直接访问图片,这是否适用?
self.finishBlock = ^{
    _image.hidden = YES;
}
2个回答

7

self被保留是因为

self.image.hidden = YES;

实际上是

[[self image] setHidden:YES];

直接保留图像是不可能的,因为在执行块且调用 [self image] 获取图像之前,它是不可用的。
你的第二个示例也保留了 self,尽管原因略有不同。在 Objective-C 中,直接访问实例变量时,实际上是通过 self 的底层结构访问的。所以,在编译后,_image 实际上是 self->_image。同样,块需要访问 self,所以会保留 self。
还值得注意的是,在任何一种情况下,如果 _image 的值在块执行之前更改,块将“看到”新值。这通常是您想要的,但并非总是如此。
避免保留 self 有两个选项。第一个选项将保留 self,并捕获定义块时 _image 的值,因此即使它发生更改,块也会看到原始值。这种方法是定义一个本地变量,将其设置为 self.image 返回的当前值,然后在块中使用它:
UIImage *image = self.image;
self.finishBlock = ^{
    image.hidden = YES;
}

另一种方法是捕获self的弱引用并在代码块中使用。在这种情况下,该代码块将对self具有弱引用,而不是强引用(即不会保留self)。但是,仍将调用self上的-image访问器方法,因此如果在代码块运行之前更改了image,则将使用新值:
__weak YourClass *weakSelf = self;
self.finishBlock = ^{
    weakSelf.image.hidden = YES;
}

请注意,在这种情况下,如果在代码块运行之前 self 被释放,那么 weakSelf 将为 nil,并且代码块中的语句将成为无操作(在 Objective-C 中,向 nil 发送消息不会产生任何作用)。

第一个示例中的方法调用非常合理。但是,在第二个示例中,self会被保留吗? - Meda
我在原回答中说错了话。我已经更新了它,使其更加全面/准确。self在你的第二个例子中仍然保留。 - Andrew Madsen
+1 对于明确指出这一点表示赞赏,但我觉得应该把问题交给 @rmaddy,因为他是第一个注意到 self->_image 这个问题的人。 - Meda

3

一个块需要保留块中捕获的所有对象。你的第一个块示例实际上是:

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

该块必须保留self,以便正确调用image方法。 由于图像是在执行块并调用image方法之前获得的,因此编写时该块无法简单地保留image。 因此,这里唯一的选择是保留self

在第二个块中,您实际上有:

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

再次强调,必须保留self,这样在实际执行块时才能访问_image实例变量的正确值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接