编辑:以下定义的问题实际上与此代码一起出现:
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与manual-retain-release [MRR]源文件中编译。并且生命周期可能在编译器和/或运行时的版本之间发生变化。
例如,调用工厂方法的ARC代码有时可以完全短路autorelease
。
听起来很可怕,但这并不是因为算法的一致性要求。由于不存在模糊行为(如普通旧MRR中所示),生命周期可能会因发布而改变,因此不会影响您的代码。
当然,这意味着您不应该在dealloc
方法之间具有顺序依赖性。这不应该是一个繁重的要求,因为在MRR下的dealloc
方法之间具有顺序依赖性总是令人讨厌的事情。
这是因为ARC仍然尊重Cocoa内存管理命名约定。您可以将属性添加到您的工厂方法person
,如下所示:+ (instancetype)person __attribute__((objc_method_family(new)));
,因此ARC假定它返回的对象带有递增的保留计数,需要与相应的版本进行平衡。然后在将变量设置为nil之后立即发生dealloc。