将局部变量分配给实例变量的 ARC 行为

ARC behavior on assigned local variable to an instance variable

问题 1

假设我有这个代码:

MyClass * __strong foo = [MyClass new];
MyClass * __strong bar = foo;
// foo = nil; // by ARC?

在引用 this answer 时,ARC 是否会自动将第 3 行的 foo 归零,因为 bar 已经获取了引用?

问题 2

//ECGService.m
@property (strong) MuttableArray *rriData;

(MuttableArray *)getRriData {
    return _rriData;
}

//AlgorithmTest.m
// according to Apple docs, local variable are marked __strong by default
MuttableArray *rriData = [self.ecgService getRriData];
for(NSNumber *rri in rriData) {
    // use rri!
}
// rriData = nil;

局部变量rriData用完后是不是应该nil掉?

而且,__strong 属性是否只能应用于一个对象的一个​​实例?

问题 1。不,您只是以两个对 MyClass 实例的引用结束。什么都没有消失。

问题 2。不,您不需要取消任何内容。 ARC 为您管理内存。这才是重点。您也永远不需要说 __strong。这是默认值。

In reference to this answer, does ARC automatically nil out foo on line 3 since bar already acquired the reference?

没有。 ARC 代表自动参考 计数 。显然计数不止于 1.

ARC 的优势在于每个引用都独立于其他引用进行处理。强 foo 保留被引用的对象,只要它指向。其他引用变量是否指向同一个对象并不重要。跟踪每个孤立的参考。

只有一种情况让ARC改变一个引用变量的值:如果它被标记为weak并且没有其他对该对象的强引用。这是预期的行为。

作为优化的结果,保留和释放可能被省略,或者源代码中的不同局部变量被放在一起。这对你来说是透明的。

Should I nil out the local variable rriData after using it?

你不应该关心这个。强引用变量会自动保留一个对象,其引用存储在引用变量中。如果它不再指向它,它会自动释放该对象。这包括

上的版本
  • 一个新值被赋给了引用变量
  • nil赋值给引用变量
  • 引用变量失去它的范围(生命周期)。

由于最后一个事实,当rriData失去它的范围时,会有一个自动生成的版本。没有理由提前取消它。

答案 1.

原则上,ARC 在超出范围之前不会“消失”foo。当它超出范围时,ARC 释放它的引用。它不必实际将 foo 设置为 nil,但效果就像 ARC 确实将其设置为 nil 一样。

实际上,通常允许 ARC 在最后一次使用 foo 变量后立即释放 foo 持有的引用,这可能在它超出范围之前很久。在您的示例中,如果您在函数中唯一使用 foo 的地方是在对 bar 的赋值中,则允许 ARC 在该赋值后立即释放 foo 的引用。请注意,通常您无法知道此早期版本,因为您不再使用 foo!另请注意 bar 仍将引用该对象,除非 bar 稍后也未在函数中使用。

有一些特殊属性可以阻止 ARC 执行此早期版本,称为 objc_precise_lifetimeobjc_returns_inner_pointer,但通常通过宏 NS_VALID_UNTIL_END_OF_SCOPENS_RETURNS_INNER_POINTER 应用。这些是您可能很快就不必担心的高级功能,但如果您想查看 NS_RETURNS_INNER_POINTER 的一些示例,请查看 NSString.h.

答案 2.

你不需要“nil out”rriData。 ARC 将在超出范围时释放其引用(或更早 - 请参阅答案 1)。

你通常不需要说__strong,因为它是默认的,而且它通常是你想要的。对一个对象有多个强引用是正常的。当您需要防止保留循环时,您可以显式使用 __weak。关于retain cycles在网上和stack overflow上有很多解释,如果你需要了解它们,请访问你喜欢的搜索引擎。