2

编辑:下面定义的问题实际上发生在这段代码中:

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        XYZPerson *myPerson = [XYZPerson person];
        myPerson = nil;
        NSLog(@"The end.");
    }
}

方法“人”是工厂方法。


我有以下代码:

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        XYZPerson *myPerson = [[XYZPerson alloc] init];
        myPerson = nil;
        NSLog(@"The end.");
    }
}

XYZPerson 覆盖了 dealloc 方法,以便它使用 NSLog 打印出一些东西。我希望上面的代码输出如下内容:

Dealloc!
The end.

但这并不像我预期的那样:

The end.
Dealloc!

我做错了什么还是我误解了 ARC 的概念?

4

2 回答 2

4

ARC 保证对象将在编译时自动进行引用计数。它更进一步,并要求代码在算法上完全一致(这在尝试转换时表现为错误,例如,void*通过id强制转换——在 ARC 下,您必须在此类强制转换中限定内存管理策略)。

ARC 不是垃圾收集器;没有扫描,没有线程,也没有停止世界的行为。这意味着以自动循环检测等为代价的行为更加可预测。

虽然 ARC 保证对象的生命周期将被自动管理,但 ARC 不保证“对象的生命周期至少与代码中使用的时间一样长,甚至可能更长”。

事实上,您可能会看到生命周期的变化取决于代码的优化级别以及您调用的工厂方法是否在 ARC 与手动保留发布 [MRR] 源文件中编译。并且生命周期可能会随着编译器和/或运行时的版本而改变。

例如,调用工厂方法的 ARC 代码有时会使整个方法短路autorelease

听起来很吓人,但这不是因为算法一致性要求。由于不能存在模棱两可的行为(就像在普通的旧 MRR 中那样),生命周期可能会随着版本的变化而改变,这不会影响您的代码。

当然,这意味着您不应该dealloc在方法之间存在顺序依赖关系。这不应该是一个繁重的要求,因为dealloc在 MRR 下的方法之间存在顺序依赖总是一件令人讨厌的事情。

于 2013-02-03T21:27:07.413 回答
0

这是因为 ARC 仍然尊重 Cocoa 内存管理命名约定。您可以像这样向您的工厂方法添加属性person+ (instancetype)person __attribute__((objc_method_family(new)));因此 ARC 假定它返回的对象带有一个递增的保留计数,该保留计数需要与相应的版本平衡。然后在将变量设置为 nil 后立即发生 dealloc。

于 2018-09-15T22:37:29.497 回答