在几个示例的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的保留计数。(请参阅下面的答案,其中包含一个完整解释它的帖子的链接。)谢谢大家!
答案 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方法也将保留它。您应该释放您分配的所有对象。 始终强>
会发生什么:
稍后取消分配 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,因此不会被释放。即时内存泄漏。
再次感谢!