目标 c - 当指针设置为 nil 时,ARC 不会解除分配(使用工厂方法)



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

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 的概念?

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

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

虽然 ARC 保证对象的生命周期将被自动管理,但 ARC 不保证超过"对象的生存时间至少与代码中使用的寿命一样长,也许更长"。

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

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

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

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

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

最新更新