3

私は現在、iOS開発に取り組もうとしています。現在、メモリ管理を理解するのに苦労しています。これが私の混乱の原因です:

NSString *path = [self.dataPath stringByAppendingPathComponent:@"dummy.plist"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
NSString *dummyKeyValue = [dict valueForKey:@"dummyKey"];

// NSLog(@"%@",[NSString stringWithString:dummyKeyValue]);

[dict release];

NSString *anotherString = [dummyKeyValue lowercaseString];

このコードは、最後の行で EXC_BAD_ACCESS エラーをトリガーします。NSDictionary がそのキー値を解放するためと思われます。私が理解していないのは、dummyKeyValue定義が考慮されていない理由です。明らかdummyKeyValueにまだ の値を指しているためです"dummyKey"

行をコメントアウトすると、次の問題、さらにおかしな現象が発生しますNSLog。何らかの方法で使用dummyKeyValueすると、それが指すメモリの解放が妨げられるようです。なぜ?

助けていただければ幸いです。

4

4 に答える 4

3

手動参照カウント モードでは、単に変数を定義しても、変数が指すオブジェクトが自動的に保持されるわけではありません。がdict解放されると、その値オブジェクトが解放され、その値オブジェクトへの強い参照を持つオブジェクトが他にない場合 (つまり、参照カウントが 0 になった場合)、それらは解放されます。それがあなたがここで見ているようです。

dummyKeyValue への強い参照を保持したい場合は、それを受け取った後も保持する必要があります。もちろん、それは、使い終わったらリリースする必要があることも意味します。これを試して:

NSString *dummyKeyValue = [[[dict valueForKey:@"dummyKey"] retain] autorelease];

現在、dummyKeyValue は、現在の自動解放プール スコープが終了するまで保持されます。多くの場合、アクセサ メソッドは値を返す前にこれを行うように記述されており、実際に見ている状況を正確に回避します。

注目に値するのは、ARC (自動参照カウント) を使用している場合、コンパイラーが必要な保持/解放呼び出しを挿入して、dummyKeyValue が処理が完了するまでスタックするようにするため、この問題は発生しないことです。

于 2013-01-23T20:56:55.337 に答える
2

これは基本的なメモリ管理です。を作成するdictと、ディクショナリは含まれるすべてのキーと値のメモリを管理します。

値を取得してdummyKeyValue変数に代入する場合、値に対して追加のメモリ管理を行うことはありません。オブジェクトを指す変数があるだけです。

を解放するdictと、辞書もすべてのキーと値を解放します。つまり、すべてのキーと値の保持カウントが 1 つ減ります。この時点では、キーと値は他に保持されていないため、すべての割り当てが解除されます。

この時点で、dummyKeyValue変数はクラッシュの原因となっている割り当て解除された値を指しています。

これを修正するにはオプションが必要です。

  1. に格納されている値を保持しますdummyKeyValue(解放する必要があります)。
  2. [dict release]最後に を使用した後に、 へのコールを移動しますdummyKeyValue

NSLogステートメントが問題を修正しているように見える理由は、あなたNSLogが autoreleased を作成するためNSStringです。これによりNSString、作成時に使用した値が保持されます。したがって、 dictが解放されたとき、 はNSStringと同じオブジェクトへの参照を保持していますdummyKeyValue。これにより、そのオブジェクトがクラッシュを防ぎ、もう少し長く存続できます。

于 2013-01-23T20:56:09.040 に答える
2

objectForKey:(から物を取得するために使用する必要がありますNSDictionary。)

まず、ARC をオンにします。Cocoa を使い始めたばかりの場合、メモリ管理以外にも環境について学ぶ必要があることがたくさんあります。ベンダーにバンドルされているコンパイラは、メモリ管理の問題の 99% を処理します。これは、新しい Cocoa 開発者にとって常に大きな障害でしたが、現在は取り除かれています。他のすべてを把握したら、後でこのトピックに戻ってください。さて、この回答の残りの部分は無視してください。ステップ3はありません。

とはいえ、これがここで起こっていることです:

を使用して辞書からオブジェクトを取得しても、そのオブジェクトのobjectForKey:所有権は取得されません。これは単なる参照であり、ディクショナリは引き続きオブジェクトを所有しています。ディクショナリを破棄すると、他のオブジェクトによっても所有 (保持) されていない限り、そのすべてのオブジェクトがディクショナリと共に移動します。ディクショナリが破棄された後もオブジェクトを存続させたい場合は、次のように要求する必要がありますretain

NSString *dummyKeyValue = [[dict objectForKey:@"dummyKey"] retain];

releaseこのように所有権を取得すると、オブジェクトの処理が完了したときに を使用するか、自動解放することによってその所有権を放棄する責任もあります。この場合、このメソッドの終了後に解放されます。

取得したオブジェクトを引数として使用してstringWithString:それを有効にすると、明らかに、信頼できない内部の詳細として、そのメソッドが引数を保持および自動解放しているためです。または、あなたが頼ることができない他の何か。これは興味深い発見ですが、オブジェクトの有効期間を管理する実用的な方法ではありません。

于 2013-01-23T20:56:42.073 に答える
0

あなたは書くべきです:

NSString *dummyKeyValue = [[dict valueForKey:@"dummyKey"] retain];

また

NSString *dummyKeyValue = [[dict valueForKey:@"dummyKey"] copy];

ARC を使用していないため、オブジェクトへの参照があるかどうかは問題ではありません。各オブジェクトには参照カウントがあります。の参照カウントdummyKeyValueは、辞書が存在するまで 1 です。解放すると、ref カウントが減少し (0 になり)、オブジェクトの割り当てが解除されます。したがって、dummyKeyValueポイントは何もありません。

ところで、オブジェクトの参照カウントを増やしたい場合はretain、 とを使用releaseして減らします。

于 2013-01-23T20:56:01.583 に答える