以下两种分配和初始化对象的方法有什么区别?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
和
self.aController= [[AController alloc] init];
大多数苹果示例使用第一种方法。为什么要分配,初始化和反对然后立即释放?
答案 0 :(得分:70)
每个对象都有引用计数。当它变为0时,该对象被解除分配。
假设该属性声明为@property (retain)
:
你的第一个例子,一行一行:
alloc
创建,其引用计数为1. self
的{{1}}方法,该方法向其发送setAController:
消息(因为该方法不知道对象的来源),递增它的引用数为2. retain
,将引用计数递减为1. 你的第二个例子基本上是第1步和第2步,但不是3,所以最后对象的引用数是2。
规则是如果你创建了一个对象,那么当你完成它时,你有责任释放它。在您的示例中,代码在设置属性后使用tempAController完成。如果需要该对象的话,调用release
是setter方法的责任。
重要的是要记住,Objective-C中的retain
实际上只是self.property = foo;
的简写,而[self setProperty:foo];
方法将根据需要保留或复制对象。
如果属性声明为setProperty:
,则该对象将被复制而不是保留。在第一个例子中,原始对象将立即释放;在第二个例子中,原始对象的引用计数将为1,即使它应该为0.所以你仍然希望以相同的方式编写代码。
如果声明属性@property (copy)
,则@property (assign)
未声明对象的所有权,而其他人则需要保留该对象。在这种情况下,第一个例子是不正确的。这些属性很少见,通常只用于对象委托。
答案 1 :(得分:30)
正如其他人所说,您展示的两个代码段并不相同(出于内存管理的原因)。 至于为何选择前者而不是后者:
后者的正确配方将是
self.aController= [[[AController alloc] init] autorelease];
与前者相比,这会通过使用自动释放池增加额外的开销,并且在某些情况下会导致对象的生命周期被不必要地延长(直到自动释放池被释放),这将增加应用程序的内存占用。
另一个“可能的”实现(取决于示例的来源)只是:
aController = [[AController alloc] init];
但是,强烈建议不要在init或dealloc方法之外的任何地方直接设置实例变量。在其他地方,你应该总是使用访问器方法。
这将我们带到示例代码中显示的实现:
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
这符合以下最佳做法:
答案 2 :(得分:5)
另请注意,您希望将代码缩减为一行,这是许多人使用Autorelease的原因:
self.aController = [[[AController alloc] init] autorelease];
虽然理论上关于iPhone的自动释放在某种程度上更加昂贵(从未听说过明确的原因),因此您可能希望在将对象分配到其他地方后立即发布。
答案 3 :(得分:5)
如果您正在使用Xcode,它可以帮助您使用静态分析器检测此类代码。 只需按Build>>建立和分析
这将在这些代码中向您显示一条非常有用的信息。
答案 4 :(得分:4)
另外需要注意的是,您的示例还取决于aController的@property定义。
如果它被定义为@property (readwrite, retain) id aController;
那么你的例子就可以了,如果它被定义为@property (readwrite, assign) id aController;
那么额外的释放调用会导致你的对象被释放。
答案 5 :(得分:2)
您也可以
@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];
带有保留属性,它的功能相同,但最好使用另一种方式(保留属性),因为它不那么混乱,代码使它看起来像你分配一个控制器然后从内存中删除,实际上它不是因为setAController保留它。