//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。第二行不会导致内存泄漏。第一行是不正确还是有办法释放内存?
答案 0 :(得分:10)
正确的行为取决于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实例保留,因此它将泄漏,除非它有匹配的版本(如第二个块)。我建议你阅读Memory Management Programming Guide [2]。
假设声明属性如上所述,您的第二个代码块是正确的。
P.S。您不应在[self.editMyObject release]
方法中使用-dealloc
。你应该调用[editMyObject release]
(假设支持@property的ivar被称为editMyObject
)。调用访问器(通过self.editMyObject
对于@synthesized访问器是安全的,但是如果覆盖访问者依赖于对象状态(可能在-dealloc
中的调用位置无效或导致其他副作用,则通过调用访问器来获取错误。
[2] Cocoa中的对象所有权规则非常简单:如果您在其签名中调用alloc
或copy
的方法(或使用基本相当于+[NSObject new]
的{{1}} [[NSObject alloc] init]
),然后您“拥有”返回的对象,您必须平衡所有权的获得与release
。在所有其他情况下,您不拥有从方法返回的对象。如果您想保留它,则必须使用retain
获得所有权,然后使用release
发布所有权。
答案 1 :(得分:8)
您的属性被声明为“retain”,这意味着传入的对象会自动保留。
因为你的对象已经有来自alloc / init的引用计数为1,所以有两个引用,我假设只有一个版本(在你的析构函数中)。
基本上,对self.editMyObject的调用实际上是这样做的;
-(void) setEditMyObject:(MyObject*)obj
{
if (editMyObject)
{
[editMyObject release];
editMyObject = nil;
}
editMyObject = [obj retain];
}
答案 2 :(得分:4)
按照惯例,在Cocoa和Cocoa-touch中,使用[[SomeClass alloc] initX]
或[SomeClass newX]
创建的任何对象都会创建一个保留计数为1的对象。您有责任在完成新实例后致电[someClassInstance release]
,通常采用dealloc
方法。
当你将新对象分配给属性而不是实例变量时,这会变得棘手。大多数属性被定义为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
使用MyObject
/ alloc
创建init
的新实例时,其保留计数为1。当您将新实例分配给self.editMyObject
时,实际上是在-setEditMyObject:
时调用编译器为您创建的@synthesize editMyObject
方法。当编译器看到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
方法释放它。)
答案 3 :(得分:3)
第一个版本创建一个没有匹配版本的对象。分配对象时,表示您是该对象的所有者。你的二传手可能会保留对象(应该如此),这意味着你现在拥有该对象两次。您需要该版本来平衡对象创建。
如果您计划使用Cocoa,则应阅读the Cocoa memory management guide。一旦你学会了它并不难,但这是你必须学习的东西,或者你会遇到很多这样的问题。
答案 4 :(得分:1)
其他人已经涵盖了导致内存泄漏的原因,所以我只想说明如何避免'temp'变量并仍然防止内存泄漏:
self.editMyObject = [[[MyObject alloc] init] autorelease];
这会使您的(retain)属性成为新对象的唯一所有者。与第二个示例完全相同的结果,但没有临时对象。
答案 5 :(得分:0)
同意并解释说下面的代码没有泄漏 (假设@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];
对我来说这看起来不错。