更新NSMenu中的项目时的内存管理

Dan*_*iel 1 cocoa memory-leaks memory-management objective-c nsmenu

我想知道这是否是在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];
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

NSG*_*God 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];
}
Run Code Online (Sandbox Code Playgroud)

请注意,通过在下部循环中autorelease创建期间添加a NSMenuItem,无需release像在代码中那样在菜单项删除期间发送额外内容.从某种意义上说,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
Run Code Online (Sandbox Code Playgroud)

  • @ user256413:使用autorelease,特别是作为一种习惯,使得忘记发布更加困难.在Mac上,当前没有风险(操作系统)会导致您的进程一次性分配过多的菜单项,最好不要冒泄漏的风险. (4认同)