目标C中的对象分配和初始化

时间:2020-03-06 14:57:39  来源:igfitidea点击:

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

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

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

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

解决方案

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

假设该属性被声明为" @property(保留)":

第一个示例,逐行:

  • 该对象由alloc创建,其引用计数为1.
  • 将对象移交给"自己"的" setAController:"方法,该方法向其发送"保留"消息(因为该方法不知道对象来自何处),将其引用计数增加到2.
  • 调用代码不再需要对象本身,因此它调用release,将引用计数减为1.

第二个示例基本上执行步骤1和2,但不执行步骤3,因此最后该对象的引用计数为2.

规则是,如果我们创建一个对象,则在使用完对象后,我们有责任释放它。在示例中,代码在设置属性后使用tempAController完成。如果需要保留该对象,则setter方法负责调用"保留"。

重要的是要记住,Objective-C中的" self.property = foo;"实际上只是" [self setProperty:foo];"的简写,并且" setProperty:"方法将根据需要保留或者复制对象。

如果该属性被声明为@property(copy),则该对象将被复制而不是保留。在第一个示例中,原始对象将立即被释放;在第二个示例中,即使原始对象的引用计数为0,也将为1. 因此,我们仍然希望以相同的方式编写代码。

如果该属性被声明为" @property(assign)",则" self"不会声明该对象的所有权,而其他人则需要保留它。在这种情况下,第一个示例将是不正确的。这类属性很少见,通常仅用于对象委托。

还请注意,我们希望将代码缩减为一行,这就是为什么许多人使用"自动发布"的原因:

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

尽管从理论上讲,iPhone的自动释放成本更高(从来没有听到过清楚的解释为什么),因此我们可能希望在将对象分配到其他位置后立即释放。

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

如果将其定义为@property(读写,保留)id aController;,则示例有效;而如果将其定义为`@property(读写,赋值)id aController;',则额外的release调用将导致对象被释放。

正如其他人指出的那样,我们显示的两个代码段不相同(出于内存管理的原因)。
关于为什么选择前者而不是后者:

后者的正确表述是

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

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

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

aController = [[AController alloc] init];

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

然后,我们将转到示例代码中所示的实现:

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

这遵循最佳实践,因为:

  • 避免自动释放;
  • 它使内存管理语义立即清晰明了;
  • 它使用访问器方法设置实例变量。

你也可以

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

具有保留属性,它的作用方式相同,但最好使用另一种方法(保留属性),因为它不那么令人困惑,该代码使它看起来像我们分配了aController,然后实际上从内存中删除这不是因为setAController保留了它。