2011-10-08 37 views
1

我想知道這是否是避免Cocoa應用程序中內存泄漏的正確方法。更新NSMenu中的項目時的內存管理

我的應用程序有更新的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中分析我的代碼,它說有潛在內存泄漏。

+1

凡沒有說潛在的內存泄漏是什麼? – bryanmac

回答

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

注意,通過建立在較低的循環中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 
+1

你不需要使用autorelease。相反,分配/初始化對象,將它們添加到菜單中,然後釋放它們。這樣就不需要使用自動釋放池了,雖然它應該總是有時候是iPhone羣體喜歡避免填滿的東西。 –

+4

@ user256413:使用autorelease,特別是作爲一種習慣,使得更難忘記發佈。在Mac上,當前沒有任何風險(當前)操作系統會殺死您的進程以便一次分配過多的菜單項,最好不要冒險泄漏。 –

+0

非常感謝那個詳細的答案! – Daniel