2

我想知道这是否是避免 Cocoa 应用程序内存泄漏的正确方法。

我的应用程序有一个更新NSMenu项目的方法:

//Remove and Release old Status Scan Menu:
if ([statusMenuScansMenu numberOfItems] !=0) {
    for (NSMenuItem *menueItemToBeReleased in [statusMenuScansMenu itemArray]) {
        [statusMenuScansMenu removeItem:menueItemToBeReleased];
        [menueItemToBeReleased release];
    }
}

//New Status Scan Menu:
for (MyObject* myObject in myArray) {
    NSMenuItem * scanMenuItem = [[NSMenuItem alloc] init];
    [scanMenuItem setTitle:[myObject name]];
    [statusMenuScansMenu addItem:scanMenuItem];
}

如您所见,在添加新项目之前,我会删除所有以前的项目并将其发送release给他们。然后我添加新的。

这是内存管理的最佳方式吗?

如果我在 Xcode 4.1 中分析我的代码,它会说存在潜在的内存泄漏。

4

1 回答 1

5

看起来你的做法应该可以正常工作,但这是一种奇怪的方式。

如果您需要 OS X 10.6+,您的代码可以合并为以下内容:

//Remove old Status Scan Menu:
[statusMenuScansMenu removeAllItems];

//New Status Scan Menu:
for (MyObject* myObject in myArray) {
    NSMenuItem * scanMenuItem = [[[NSMenuItem alloc] 
      initWithTitle:[myObject name] action:NULL keyEquivalent:@""] autorelease];
    [statusMenuScansMenu addItem:scanMenuItem];
}

请注意,通过在下部循环autorelease的创建过程中添加一个NSMenuItem,无需release像在您的代码中那样在菜单项删除期间发送额外的内容。在某种意义上,an对子菜单和它包含的菜单项的NSMenu行为类似于:它保留它们。NSArray因此,由于您将新创建的NSMenuItem直接插入到 中NSMenu,就好像NSMenu正在获取菜单项的所有权。因此,您需要抵消从项目的 alloc/init 创建中获得的 +1 保留计数,以确保不会发生内存泄漏。在您的代码中,您通过在菜单项删除期间向其发送显式/额外释放来抵消 +1 保留计数,这是一种迂回。在我发布的上述代码中,通过添加autorelease在下部循环中创建期间,唯一“保留”菜单项的将是菜单。然后,稍后,当您调用该removeAllItems方法时,菜单将向release每个菜单项发送一个,此时它们的保留计数应降至 0,并且它们将被释放。

如果你需要支持 10.6 之前的 OS X 版本,你可以使用上面的代码,除了[statusMenuScansMenu md_removeAllItems]. [statusMenuScansMenu removeAllItems]然后,您可以md_removeAllItems在一个类别中创建此方法,NSMenu如下所示:

@interface NSMenu (MDAdditions)
- (void)md_removeAllItems;
@end


@implementation NSMenu (MDAdditions)
- (void)md_removeAllItems {
    NSUInteger currentCount = [self numberOfItems];
    for (NSUInteger i = 0; i < currentCount; i++) {
        [self removeItemAtIndex:0];
    }
}
@end
于 2011-10-08T02:02:55.927 回答