Objective C中的对象分配和初始化

时间:2008-10-01 04:31:44

标签: objective-c cocoa cocoa-touch memory-management

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

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

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

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

6 个答案:

答案 0 :(得分:70)

每个对象都有引用计数。当它变为0时,该对象被解除分配。

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

你的第一个例子,一行一行:

  1. 该对象由alloc创建,其引用计数为1.
  2. 将对象移交给self的{​​{1}}方法,该方法向其发送setAController:消息(因为该方法不知道对象的来源),递增它的引用数为2.
  3. 调用代码不再需要对象本身,因此它调用retain,将引用计数递减为1.
  4. 你的第二个例子基本上是第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>>建立和分析

alt text

这将在这些代码中向您显示一条非常有用的信息。

alt text

答案 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保留它。