//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];

对我来说这看起来不错。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top