在objective-c中分配/初始化/保留对象的不同方法

时间:2010-06-01 06:26:46

标签: iphone objective-c memory memory-management

在几个示例的Objective-c代码中,我看到人们创建了这样的新对象:


RootViewController *viewController = [[RootViewController alloc] init];
self.rootViewController = viewController; // self.rootViewController is a (nonatomic,retain) synthesized property
[viewController release];
[window addSubview: [self.rootViewController view]];

与幕后相比,这有什么不同吗?


self.rootViewController = [[RootViewController alloc] init];
[window addSubview: [self.rootViewController view]];

编辑:以后我在dealloc方法中发布了rootViewController:


-(void) dealloc {
    [rootViewController release];
    [super dealloc];
}

我只是对两者之间的语法感到好奇。一个似乎创建一个临时的viewController对象,另一个直接分配/ inits到self.rootViewController。

看起来有点简单/精简,所以我想知道为什么有人会选择第一种方法。

谢谢!

答案: 因此,当使用第二种方法时,它会导致内存泄漏,因为rootViewController对象实际上具有2的保留计数。(请参阅下面的答案,其中包含一个完整解释它的帖子的链接。)谢谢大家!

5 个答案:

答案 0 :(得分:3)

这一行:

self.rootViewController = viewController

与此行相同:

[self setRootViewController:viewController];

典型的setX调用将释放先前保留的X值并指定新的保留值X。

id old = X;
X = [new retain];
[old release];

但它也可以做任何事情。

如果您知道没有要释放的当前值(在init中)并且setter函数除了保留新值(合成)之外什么都不做,您可以替换:

RootViewController *viewController = [[RootViewController alloc] init];
self.rootViewController = viewController; // self.rootViewController is a (nonatomic,retain) synthesized property
[viewController release];

使用:

rootViewController = [[RootViewController alloc] init];

不使用self.,因此直接分配值而不是调用setter方法。通常首选使用setter方法。

要根据需要合并线条,您还可以切换到:

self.rootViewController = [[[RootViewController alloc] init] autorelease];

使用setter方法,释放已分配的实例,并适合一行。

答案 1 :(得分:2)

您的第二个代码snipppet不会释放您创建的对象。

self.rootViewController是一个保留对象的属性。所以你使用alloc创建一个对象,然后self.rootViewController的setter方法也将保留它。您应该释放您分配的所有对象。 始终

会发生什么:

  1. 使用 alloc 创建RootViewController类型的对象,因此保留计数变为 1
  2. 将对象分配给也保留对象的属性。因此,保留计数变为 2
  3. 稍后取消分配 self 时,将释放保留的RootViewController对象,因此其保留计数再次变为 1

    结果:您有内存泄漏。

答案 2 :(得分:1)

在第二个代码段中会出现内存泄漏,因为您省略了[self.rootViewController release]行。

更详细:

  • 当您致电[[RootViewController alloc] init]时,所创建对象的保留计数将为1。
  • 调用self.rootViewController = viewController会将其增加为2,因为self.rootViewController属性正在保留。
  • 调用[viewController release]会将保留计数减少到1
  • 因此,如果稍后调用self.rootViewController = nil,则保留计数将为0(因为生成的setter调用release方法),因此该对象将被释放。

在第二种情况下,当您调用self.rootViewController = nil时,保留计数将为1,因此该对象永远不会被释放。

如果您想要更紧凑的解决方案,请尝试以下方法:

self.rootViewController = [[[RootViewController alloc] init] autorelease];
[window addSubview: [self.rootViewController view]];

答案 3 :(得分:0)

请阅读并理解Cocoa Memory MAnagement Rules。您使用alloc获取了对象,因此您拥有它的所有权。 “你”是指当前范围内的执行代码。您需要释放或自动释放它以放弃所有权。将对象分配给其他东西(在本例中为属性)并不能免除您在完成后放弃所有权的责任。

你的第二个例子泄露了。你可以这样解决它:

self.rootViewController = [[[RootViewController alloc] init] autorelease];

在Mac OS X中,无论您使用它还是您的第一个示例,都只是首选样式的问题。对于iPhone,第一个示例通常是首选,因为它不涉及将对象添加到自动释放池。话虽如此,由于视图控制器可能需要在当前事件结束之后保持不变,因此它几乎没有区别。

顺便说一句,两个答案都提到了保留计数,它们都是正确的,但最好不要考虑保留计数,只考虑所有权。保留计数是一个实现细节。

答案 4 :(得分:0)

谢谢你们的回答!我一直在寻找较少的“阅读内存管理指南”类型的答案,更多的是“愚蠢的”,“这里是为你提供这两种方法的背景和区别”的答案类型。我熟悉对象所有权,保留计数等,但我没有意识到为什么使用** self。** rootViewController很重要,为什么第二个代码片段泄漏...以及字面意思是“幕后”两者之间的差异。所以我遇到了这个帖子,我觉得这是我正在寻找的确切答案...(我希望它是准确的!):)但是无论如何我正在给Philippe的Ole复选标记,因为他先回答。在阅读以下帖子之前,我才明白他的答案......

http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-properties-newbie.html

这部分对我来说很关键:


如果你写下来会发生什么:

  

self.obj = [[SomeObject alloc] init];

在这种情况下,你持有一个保留计数为2的对象 - 第一个计数来自“alloc”,第二个计数来自setter。

要发布此变量,您必须执行以下操作:

[obj release];
self.obj = newValue;

以便在对象上调用“release”两次。如果省略额外的“释放”,那么当指针被覆盖时,对象仍然会浮动,保留计数为1,因此不会被释放。即时内存泄漏。


再次感谢!