为什么这会造成内存泄漏(iPhone)?
-
03-07-2019 - |
题
//creates memory leak
self.editMyObject = [[MyObject alloc] init];
//does not create memory leak
MyObject *temp = [[MyObject alloc] init];
self.editMyObject = temp;
[temp release];
第一行代码会产生内存泄漏,即使您在类的dealloc方法中执行[self.editMyObject release]也是如此。 self.editMyObject的类型为MyObject。第二行不会导致内存泄漏。第一行是不正确还是有办法释放内存?
解决方案
正确的行为取决于editMyObject @property的声明。假设它被视为
@property (retain) id editMyObject; //id may be replaced by a more specific type
或
@property (copy) id editMyObject;
然后通过 self.editMyObject =
进行分配,保留或复制分配的对象。由于 [[MyObject alloc] init]
返回一个保留对象,你作为调用者拥有,你有一个额外的MyObject实例保留,因此它将泄漏,除非它有匹配的版本(如在第二个块)。我建议你阅读内存管理编程指南 [2]。
假设声明属性如上所述,您的第二个代码块是正确的。
P.S。您不应在 -dealloc
方法中使用 [self.editMyObject release]
。你应该调用 [editMyObject release]
(假设支持@property的ivar被称为 editMyObject
)。调用访问器(通过 self.editMyObject
对@synthesized访问器是安全的,但是如果覆盖访问器依赖于对象状态(在 -dealloc
或导致其他副作用,你通过调用访问者有一个错误。
[2] Cocoa中的对象所有权规则非常简单:如果在其签名中调用 alloc
或 copy
的方法(或使用 + [NSObject new]
,它基本上等同于 [[NSObject alloc] init]
),然后你“拥有”返回的对象,您必须在所有权的获得与 release
之间取得平衡。在所有其他情况下,您不拥有从方法返回的对象。如果你想保留它,你必须使用 retain
获得所有权,然后通过 release
释放所有权。
其他提示
您的财产被声明为“保留”意味着传入的对象会自动保留。
因为你的对象已经有来自alloc / init的引用计数为1,所以有两个引用,我假设只有一个版本(在你的析构函数中)。
基本上,对self.editMyObject的调用实际上是这样做的;
-(void) setEditMyObject:(MyObject*)obj
{
if (editMyObject)
{
[editMyObject release];
editMyObject = nil;
}
editMyObject = [obj retain];
}
按照惯例,在Cocoa和Cocoa-touch中,使用 [[SomeClass alloc] initX]
或 [SomeClass newX]
创建的任何对象都会创建一个保留计数为1的对象。当您完成新实例时,通常在 dealloc
方法中,您负责调用 [someClassInstance release]
。
当你将新对象分配给属性而不是实例变量时,这会变得棘手。大多数属性被定义为 retain
或 copy
,这意味着它们可以在设置时增加对象的保留计数,或者创建对象的副本,保持原始状态不变。
在您的示例中,您可能在 .h
文件中包含此内容:
@property (retain) MyObject *editMyObject;
所以在你的第一个例子中:
// (2) property setter increments retain count to 2
self.editMyObject =
// (1) new object created with retain count of 1
[[MyObject alloc] init];
// oops! retain count is now 2
使用 alloc
/ init
创建 MyObject
的新实例时,它的保留计数为1。将新实例分配给 self.editMyObject
时,实际上是在 @synthesize editMyObject <时调用编译器为您创建的
-setEditMyObject:
方法。 /代码>。当编译器看到 self.editMyObject = x
时,它会用 [self setEditMyObject:x]
替换它。
在你的第二个例子中:
MyObject *temp = [[MyObject alloc] init];
// (1) new object created with retain count of 1
self.editMyObject = temp;
// (2) equivalent to [self setEditMyObject: temp];
// increments retain count to 2
[temp release];
// (3) decrements retain count to 1
你坚持你的新对象足够长时间来释放它,所以保留计数是平衡的(假设你在 dealloc
方法中释放它。)
另请参阅指针/内存管理的可可策略
第一个版本创建一个没有匹配版本的对象。分配对象时,表示您是该对象的所有者。你的二传手可能会保留对象(应该如此),这意味着你现在拥有该对象两次。您需要该版本来平衡对象创建。
您应该阅读 Cocoa内存管理指南你打算一直使用Cocoa。一旦你学会了它并不难,但这是你必须学习的东西,或者你会遇到很多这样的问题。
其他人已经涵盖了导致内存泄漏的原因,所以我只想说明如何避免'temp'变量并仍然防止内存泄漏:
self.editMyObject = [[[MyObject alloc] init] autorelease];
这会使您的(retain)属性成为新对象的唯一所有者。与第二个示例完全相同的结果,但没有临时对象。
同意并解释说下面的代码没有泄漏 (假设@property保留并且@synthesize用于editMyObject):
//does not create memory leak
MyObject *temp = [[MyObject alloc] init];
self.editMyObject = tempt;
[temp release];
问题:以下代码没有使用临时指针有什么问题吗?
//does not create memory leak ?
self.editMyObject = [[MyObject alloc] init];
[editMyObject release];
对我来说这看起来不错。