我想知道这是否是避免 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 中分析我的代码,它会说存在潜在内存泄漏。
最佳答案
看起来您的做法应该可能可以正常工作,但这是一种奇怪的方法。
如果您需要 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];
}
请注意,通过在下层循环中创建 NSMenuItem
期间添加 autorelease
,无需发送额外的 release
在菜单项删除过程中,就像您的代码中一样。从某种意义上说,NSMenu
的作用类似于 NSArray
对其包含的子菜单和菜单项的作用:它保留它们。因此,由于您将新创建的 NSMenuItem
直接插入到 NSMenu
中,就好像 NSMenu
正在获取菜单项的所有权。因此,您需要抵消从项目的 alloc/init 创建中获得的 +1 保留计数,以确保不会发生内存泄漏。在您的代码中,您通过在菜单项删除期间向其发送显式/额外释放来抵消 +1 保留计数,这是一种迂回。在我发布的上面的代码中,通过在下部循环的创建过程中添加 autorelease
,唯一“保留”菜单项的就是菜单。然后,稍后,当您调用 removeAllItems
方法时,菜单将向每个菜单项发送 release
,此时它们的保留计数应降至 0,并且它们'将被释放。
如果您需要支持 10.6 之前的 OS X 版本,可以使用上述代码,但需要用 [statusMenuScansMenu md_removeAllItems]
替换 [statusMenuScansMenu removeAllItems]
。然后,您可以在 NSMenu
上的类别中创建此 md_removeAllItems
方法,如下所示:
@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
关于objective-c - 更新 NSMenu 中的项目时的内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7694042/