目标C中的对象分配和初始化
以下两种分配和初始化对象的方式有什么区别?
AController *tempAController = [[AController alloc] init]; self.aController = tempAController; [tempAController release];
和
self.aController= [[AController alloc] init];
大多数的苹果例子使用第一种方法。 为什么要分配init和object,然后立即释放?
每个对象都有一个引用计数。 当它到0时,对象被释放。
假设该属性被声明为@property (retain)
:
你的第一个例子,逐行:
- 该对象由
alloc
创build,它的引用计数为1。 - 该对象被交给
self
的setAController:
方法,该方法发送一个retain
消息(因为该方法不知道对象来自哪里),将其引用计数递增为2。 - 调用代码不再需要该对象本身,因此它调用
release
,将引用计数递减为1。
你的第二个例子基本上做的第一步和第二步,但不是3,所以最后对象的引用计数是2。
规则是,如果你创build一个对象,当你完成它时,你有责任释放它。 在你的例子中,代码是在tempAController设置属性后完成的。 如果需要该对象retain
存在,那么调用retain
方法的责任是调用retain
。
记住self.property = foo;
是很重要的self.property = foo;
在Objective-C中实际上只是[self setProperty:foo];
简写[self setProperty:foo];
并且setProperty:
方法将根据需要保留或复制对象。
如果该属性被声明为@property (copy)
,则该对象将被复制而不是被保留。 在第一个例子中,原始对象将被立即释放; 在第二个例子中,原始对象的引用计数应该是1,即使它应该是0.所以你仍然希望以相同的方式编写你的代码。
如果该属性被声明为@property (assign)
,那么self
不会声明对象的所有权,而其他人则需要保留它。 在这种情况下,第一个例子是不正确的。 这些属性很less见,通常只用于对象代表。
正如其他人已经指出,你展示的两个代码片段是不相同的(由于内存pipe理的原因)。 至于为什么select前者:
后者的正确表述是
self.aController= [[[AController alloc] init] autorelease];
与前者相比,这增加了额外的开销,通过使用autorelease池,并在某些情况下会导致对象的生命周期不必要的扩展(直到autorelease池被释放),这将增加您的应用程序的内存足迹。
其他“可能的”实现(取决于示例的来源)只是简单的:
aController = [[AController alloc] init];
但是,直接设置一个实例variables,除了在init或dealloc方法之外,其他任何地方都不鼓励。 在其他地方,你应该总是使用访问器方法。
这使我们看到示例代码中显示的实现:
AController *tempAController = [[AController alloc] init]; self.aController = tempAController; [tempAController release];
这是遵循最佳做法,因为:
- 它避免了autorelease;
- 它使内存pipe理语义立即清晰;
- 它使用访问器方法来设置实例variables。
还要注意,将代码缩减到一行的愿望是为什么许多人使用Autorelease:
self.aController = [[[AController alloc] init] autorelease];
虽然在理论上iPhone的autorelease在某种程度上更昂贵(从来没有听清楚的解释,为什么),因此你可能希望明确释放后,你分配对象的其他地方。
如果您使用的是Xcode,它可以帮助您使用静态分析器来检测这些代码。 只需点击Build >> Build and Analyze
这会在这样的代码中向你显示非常有用的信息。
另外要注意的是,你的例子也依赖于aController的@property定义。
如果它被定义为@property (readwrite, retain) id aController;
那么你的例子工作,而如果它被定义为@property (readwrite, assign) id aController;
那么额外的调用释放将导致您的对象被释放。
你也可以做
@property (nonatomic, retain)AController *aController; ... self.aController= [[AController alloc] init]; [aController release];
有一个保留的属性,它会以同样的方式工作,但它更好地使用其他方式(保留属性),因为它不那么混乱,代码使它看起来像你分配一个控制器,然后从内存中删除,实际上它不会因为setAController保留它。