块隐式保留'self'; - 但这是有意的行为吗?

Block implicitly retains 'self'; - but is it intended behaviour?

昨天我的最新 iOS 构建 运行 在 Xcode 上没有警告。在一夜之间升级到版本 9.3 (9E145) 后,我收到了多个警告。当我尝试 self->score 跟随 answer (1) 到一个类似的问题时,警告消失了。

但在最近的 answer (2) 同一个问题中,通过更改设置解决了该问题。目前我对 Apple LLVM 9.0 - Warnings -Objective C and ARC 的设置是

Implicit retain of ‘self’ within blocks Yes

但我不明白Block implicitly retains 'self'在下面代码的上下文中是什么意思,所以我不能说这种行为是否是“有意的” .或者我是解决了一个问题还是只是隐藏了它。或者答案 1 是否比答案 2 更好。

有人可以解释一下 Block implicitly retains 'self' 在这种情况下的含义吗?谢谢。

score.alpha = 1.0;

if (sequenceState >= STATES_Count)
{
    [GraphicScore animateWithDuration:8.0f
                                delay:1.0f
                              options:UIViewAnimationOptionCurveEaseOut
                           animations:^{self->score.alpha = 0.0;} // animations:^{score.alpha = 0.0;}
                           completion:^(BOOL finished){ }];
}
[self addSubview:score];

鉴于:

- (void)bobIsYourUncle {
   ^{score.alpha = 0.0;}();
}

其中score是实例变量,实例变量通过self访问。因为块可能在某处排队并稍后执行,所以块在创建时保留self

因为 ivar 访问 invisibly 通过 self 取消引用,所以 implicit retain 在代码中有点不明显。编译器在 ivar 前面添加 self-> 的相当丑陋的建议至少使得 self 被块捕获是显而易见的。

所以,是的,这是正确的行为。而且,是的,有时需要它。您可以通过在创建块之前获取 ivar 的值(在局部变量中)来避免它,但您还必须知道这样做 会更改获取 ivar 值的时间 并且这可能会导致行为改变。

这条关于对 self 的隐式引用的警告很有用,因为如果没有它,在查看代码时并不总是很明显哪些块有引入强引用循环的风险,哪些没有.通过鼓励程序员使这些 self 引用显式(例如 Swift 等安全编程语言所要求的),您最终得到的代码可以清楚地看到强引用循环是否是一个潜在的问题与否。

因此,我鼓励您将警告保持打开状态,但继续使用 self-> 显式显示那些隐式 self 引用(ivars),或者,如果使用属性,self.,正如您引用的第一个答案所建议的那样。

然后您可以检查 self 闭包的那些单独使用,并确保它们不会引入任何强引用循环的实际风险。如果他们这样做,您可以根据需要采用 weakSelfweakSelf/strongSelf 模式。