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ある意味では、サブメニューとそれに含まれるメニュー項目のNSMenuように動作します。つまり、それらを保持します。NSArrayつまり、新しく作成したものNSMenuItemをに直接挿入しているNSMenuのでNSMenu、メニュー項目の所有権を取得しているように見えます。そのため、メモリリークが発生しないように、アイテムのalloc/init作成から取得する+1保持カウントを打ち消す必要があります。あなたのコードでは、メニュー項目の削除中に明示的/追加のリリースを送信することで、+1の保持カウントを打ち消していました。これは一種の回り道です。私が投稿した上記のコードでは、autorelease下のループで作成している間、メニュー項目を「保持」するのはメニューだけです。その後、removeAllItemsメソッドを呼び出すと、メニューは各メニュー項目にを送信しますrelease。その時点で、保持カウントは0に下がり、割り当てが解除されます。

10.6より前のバージョンのOSXをサポートする必要がある場合は、の代わり[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 に答える