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