【问题标题】:Releasing With NSMutableArray?使用 NSMutableArray 发布?
【发布时间】:2010-12-27 06:12:12
【问题描述】:

我在 main 中分配 myMDD,其中包含一个 NSMutableArray 实例变量(在 init 中分配/初始化)。当我将项目添加到 NSMutableArray (frameList) 时,我会在添加后释放。数组和它现在包含的对象在 main 的底部释放。

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    MDD *myMDD = [[MDD alloc] init];
    Frame *myFrame = [[Frame alloc] init];

    [myMDD addFrame:myFrame];

    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
    [inFrame release];
}

// METHOD_ mdd dealloc
-(void)dealloc {
    NSLog(@"_deal...: %@", self);
    [frameList release];
    [super dealloc];
}

我的问题是“静态分析器”报告了潜在的内存泄漏,更愿意将框架添加到 main 中。 (即)

 int main (int argc, const char * argv[]) {

    ...

 [myFrame release]; // Added
    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
    // [inFrame release];
}

我知道为什么会这样,如果我分配 myMDD 并且从不调用 addFrame 那么我需要释放它。也许这只是将自动释放添加到 myMDD 的一种情况,但是在我调用 addFrame 并且 NSMutableArray 正在释放对象的情况下,这会起作用吗?

EDIT_001

改为...

int main (int argc, const char * argv[]) {
    ...
    [myMDD addFrame:myFrame];
    [myFrame release];
    myFrame = nil;

    [myMDD release];
    [pool drain];
    return 0;
}

// METHOD_ mdd addFrame:
-(void)addFrame:(Frame*) inFrame {
    [frameList addObject:inFrame];
}

加里

【问题讨论】:

  • Re EDIT_001:你不需要nil 出一个变量,除非你用它来保存一个缓存(所以nil 意味着“需要(重新)创建缓存”)。你几乎不需要 nil 出像 myFrame 这样的局部变量。
  • 嗨彼得,myFrame 是一个指向对象的指针,没有 nil 是否不安全,因为我已经发布了它指向的内容?我的印象是 nil 指针更好,因为消息可以发送到 nil,但不能发送到不存在的对象?
  • 这就是我们所说的dealloc 方法。如果您要向已解除锁定(或正在解除锁定)的对象的任何变量中的指针发送消息,那么您做错了。最好立即崩溃并找出该错误,而不是将消息发送到nil 并因此隐藏错误。

标签: objective-c cocoa


【解决方案1】:

您收到该警告的原因是因为 NSMutableDArray 保留了放入其中的任何对象;同样,当NSMutableArray 被释放时,它也会释放其中包含的任何对象。那么让我们看看你的代码。

这一行:

Frame *myFrame = [[Frame alloc] init];

创建一个名为myFrameFrame 的新实例。 myFrame 的保留计数为 1,因为您使用 alloc/init 创建它。

然后你将它传递给addFrame::

[myMDD addFrame:myFrame];

然后将其放入NSMutableArray 的实例中:

[frameList addObject:inFrame];

此时,inFramemyFrame 指向同一个对象。当添加到数组中时,这个对象的保留计数会增加,所以现在是 2。

稍后,回到main,你释放myMDD,它释放frameList。假设 frameList 现在的保留计数为 0,它被释放 - 作为 NSMutableArray,它释放它包含的任何对象,其中包括指向我的 myFrame 的对象。

所以现在myFrame 的保留计数是 1...所以它没有被释放,并且您有内存泄漏。

解决问题的一种 Cocoa 方式是通过自动释放 myFrame

Frame *myFrame = [[[Frame alloc] init] autorelease];

这意味着它不会泄漏。然后,在第二个示例 (Edit_001) 中使用 -[MDD dealloc] 方法。你是对的,你不应该在你的 addFrame 方法中释放 inFrame,因为你没有保留它。

【讨论】:

  • 感谢 mipadi,现在我将使用 EDIT_001 并从 addFrame 中删除版本,我明白为什么现在这不是一个好主意。至于 myFrame,我将按照 EDIT_001 再次在 main() 中发布它,我很感激我也可以按照您的建议使用 autorelease。
【解决方案2】:

按照惯例,add 方法应该只在需要时保留对象,而不是释放它。作为一般规则,您不应释放未保留的对象,在您的示例中,您保留(创建)框架的范围与 addFrame 方法中的范围不同。

范围是指逻辑范围,而不是语言范围。

在该特定示例中,您必须在 addFrame 之后调用 release。但是释放不应该在addFrame方法中。

【讨论】:

  • 感谢 Nicolas,这是有道理的,方法中的发布感觉更整洁,但我感觉我做事的方式并不正确。再次感谢。
【解决方案3】:

在大多数情况下,Cocoa 提供了初始化并返回对象的自动发布版本的类方法。即[NSMutableDictionary dictionary] vs [[NSMutableDictionary alloc] init]

如果您要创建不需要保留的对象,或者要将其存储在集合中(NSArray、NSDictionary、NSSet 等),我建议始终尽可能使用类方法。

然后,一般规则是只分配您的类直接拥有的对象(即实例或类变量,而不是在集合内),并在所有其他情况下使用类方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多