56

以下两种分配和初始化对象的方法有什么区别?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

self.aController= [[AController alloc] init];

大多数苹果示例使用第一种方法。为什么要分配、初始化和对象然后立即释放?

4

6 回答 6

71

每个对象都有一个引用计数。当它变为 0 时,对象被释放。

假设该属性被声明为@property (retain)

您的第一个示例,逐行:

  1. 该对象由 创建alloc,它的引用计数为 1。
  2. 对象被移交给self'ssetAController:方法,该方法向它发送一条retain消息(因为该方法不知道对象来自哪里),将其引用计数增加到 2。
  3. 调用代码不再需要对象本身,因此它调用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则不声明该对象的所有权,并且其他人需要保留它。在这种情况下,第一个示例将不正确。这类属性很少见,通常仅用于对象委托。

于 2008-10-01T04:54:29.090 回答
31

正如其他人所指出的,您显示的两个代码片段并不等效(出于内存管理原因)。至于为什么选择前者而不是后者:

后者的正确表述是

self.aController= [[[AController alloc] init] autorelease];

与前者相比,这通过使用自动释放池增加了额外的开销,并且在某些情况下会导致对象的生命周期被不必要地延长(直到自动释放池被释放),这将增加您的应用程序的内存占用。

另一个“可能的”实现(取决于示例的来源)很简单:

aController = [[AController alloc] init];

但是,强烈建议不要在 init 或 dealloc 方法之外的任何地方直接设置实例变量。在其他地方,您应该始终使用访问器方法。

这将我们带到示例代码中显示的实现:

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

这遵循最佳实践,因为:

  • 它避免了自动释放;
  • 它使内存管理语义立即清晰;
  • 它使用访问器方法来设置实例变量。
于 2008-10-03T16:37:03.277 回答
5

另请注意,您希望将代码减少到一行是许多人使用 Autorelease 的原因:

self.aController = [[[AController alloc] init] autorelease];

尽管理论上 iPhone 的自动释放在某种程度上更昂贵(从未听到过明确的解释),因此您可能希望在将对象分配到其他位置后立即显式释放。

于 2008-10-01T07:03:56.550 回答
5

如果您使用的是 Xcode,它可以帮助您使用静态分析器检测此类代码。只需点击构建>>构建和分析

替代文字

这将在这些代码片段中向您显示非常有用的消息。

替代文字

于 2011-01-14T18:07:04.467 回答
4

需要注意的另一件事是,您的示例还取决于 aController 的 @property 定义。

如果将其定义为,@property (readwrite, retain) id aController;则您的示例有效,而如果将其定义为,@property (readwrite, assign) id aController;则对 release 的额外调用将​​导致您的对象被释放。

于 2008-10-01T18:38:04.743 回答
2

你也可以做

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

具有保留属性,它会以相同的方式运行,但最好使用其他方式(用于保留属性),因为它不那么令人困惑,该代码使它看起来像你分配了一个控制器,然后它从内存中删除,实际上不是因为 setAController 保留了它。

于 2009-08-04T00:24:53.543 回答