2010-12-05 10 views
2

Leaksツールを実行していて、辞書のmutableDeepCopyで大量のリークが検出されましたが、コードに何が間違っているかわかりません。助言がありますか?iPhoneでメモリリークを修正する方法がわからない

@interface RootViewController : UIViewController{ 

    NSDictionary *immutableDictionary; 
    NSMutableDictionary *mutableDictionary; 
} 

ここでここで楽器に

self.mutableDictionary = [self.immutableDictionary mutableDeepCopy]; 

を強調表示のコードの行は、ここで辞書

@interface NSDictionary(MutableDeepCopy) 
    -(NSMutableDictionary *)mutableDeepCopy; 
@end 

の可変コピーを作成するための方法であるが、私は「、メソッドの実装です漏れが100%漏れているというコードを強調しました

- (NSMutableDictionary *) mutableDeepCopy { 
    NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]]; 
    NSArray *keys = [self allKeys]; 

    for(id key in keys) { 
     id value = [self valueForKey:key]; 
     id copy = nil; 
     if ([value respondsToSelector:@selector(mutableDeepCopy)]) { 
      copy = [value mutableDeepCopy]; 
     } else if ([value respondsToSelector:@selector(mutableCopy)]) { 
      copy = [value mutableCopy]; //This is the Leak 
     } 
     if (copy == nil) { 
      copy = [value copy]; 
     } 
     [dictionaryToReturn setValue:copy forKey:key]; 
    } 
    return dictionaryToReturn; 
} 
+0

valueForKeyではなく/ setObject:forKey:/ setValueForKey:後者はKVC用に設計されていますが、NSDictionary上ではほとんど同じことをしていますが、よりゆっくりと微妙な違いがあります。 – JeremyP

+0

チップJeremyのおかげで – aahrens

答えて

3

アップルのMemory Management Rulesに照らしてこれを分析する必要があります。この行を皮切り

self.mutableDictionary = [self.immutableDictionary mutableDeepCopy]; 

私はmutableDeepCopyは私が所有するオブジェクトを返すことを期待するので、いくつかの点で私はそれを解放するか、自動解放する必要があります。例えば

NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy]; 
self.mutableDictionary = temp; 
[temp release]; 

または

self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease]; 

だから今、私たちはmutableDeepCopyを見てする必要があります。名前に「コピー」があるので、実際には返されたオブジェクトを解放することを「忘れる」ことを意味する「所有」オブジェクトを返す必要があります。最初の行に返されたオブジェクトを作成するときには、dictionaryWithCapacity:は所有していないオブジェクトを提供しているので、すでにそれを実行していません。

NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]]; 

これであなたはそれを所有しています。

mutableDeepCopyは、mutableDeepCopy、mutableCopy、およびcopyから返されたオブジェクトをまったく同じ方法で扱うことができるため、ルールに従うことが重要です。 3つのケースでは、配列に挿入するオブジェクトコピーを所有しています。あなたが所有しているので、あなたはそれを解放しなければなりません。そうしないと、漏れてしまいます。だから、ループの最後に、あなたが必要です

[copy release]; 

それはリークを停止します。

+0

素晴らしい説明ジェレミー。それは私をたくさん助けました。 – aahrens

+0

@aahrens:問題ありません – JeremyP

2

mutableCopyは、オブジェクトの保持カウントを増やします(setValue:forKey:)。これは、dictionaryToReturnがdeallocされている場合、mutableCopyがまだ呼び出されていたオブジェクトの保持カウントが1であることを意味します。

は、代わりにこれをやってみてください。

copy = [[value mutableCopy] autorelease]; 
+0

それは動作するように見えますが、私がInstrumentsを実行しているときに、そのコードを実行しようとするとアプリケーションがクラッシュします。しかし、私はちょうどアプリを使用しているときに私はクラッシュを見ていない。 – aahrens

+0

Odd。覚えておいてください(Eikoのように)、名前に "copy"という単語を含むメソッドは、保持カウント+1のオブジェクトを返さなければなりません。 mutableCopyとcopyはすでに行いますが、あなたのmutableDeepCopyメソッドはそうしません。それに応じて、メソッド変数と返されたオブジェクトのメモリ管理を調整し、別のショットを付けます。 –

3

あなたの財産が宣言されている方法は?これがretainまたはcopyの場合、これはリークしません。

問題は、名前がmutableDeepCopyの場合、保持されているオブジェクトが返され、実際にはオートレリースされたオブジェクトは返されないということです。

編集: そしてmutableDeepCopy自体で、あなたは辞書に追加した後copy変数を解放する必要があります。

+0

どちらの不動産についてお知りになりたいですか?両方のディクショナリには、(nonatomic、retain)プロパティが指定されています。 – aahrens

+0

私は、2番目のコードブロックで使用するmutableDictionaryプロパティを意味していました。 – Eiko

関連する問題