目分配和init在目标C
-
03-07-2019 - |
题
之间的区别是什么下面的2种方式分配和init一对象?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
和
self.aController= [[AController alloc] init];
大多数的苹果如使用第一种方法。为什么你会分配,init和目的,然后立即释放?
解决方案
每个对象都有引用计数。当它变为0时,该对象被解除分配。
假设该属性声明为 @property(retain)
:
你的第一个例子,一行一行:
- 该对象由
alloc
创建,其引用计数为1. - 该对象被移交给
self
的setAController:
方法,该方法向其发送retain
消息(因为该方法不知道对象来自哪里),将其引用计数增加到2。 - 调用代码不再需要对象本身,因此它调用
release
,将引用计数递减为1.
醇>
你的第二个例子基本上是第1步和第2步,但不是3,所以最后对象的引用数是2。
规则是如果你创建了一个对象,那么当你完成它时,你有责任释放它。在您的示例中,代码在设置属性后使用tempAController完成。如果需要该对象的话,调用 retain
是setter方法的责任。
重要的是要记住,Objective-C中的 self.property = foo;
实际上只是 [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,它可以帮助您使用静态分析器检测此类代码。 只需按Build>>建立和分析
这将在这些代码中向您显示一条非常有用的信息。
另外需要注意的是,您的示例还取决于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保留它。