web-dev-qa-db-ja.com

メモリリークを発生させずにカスタムオブジェクトのNSMutableArrayをクリアする方法

カスタムオブジェクトのNSMutableArrayがある場合、メモリの問題を引き起こさずに配列を簡単にクリアするにはどうすればよいですか?カスタムオブジェクトクラスには、インスタンス変数などを正しく解放するdeallocメソッドが含まれていると仮定します。

たとえば、NSArrayの「removeAllObjects」メソッドを使用しても問題ありませんか?

  • はいの場合-これはどのように機能しますか-「removeAllObjects」は、オブジェクトを削除するときに各オブジェクトの「dealloc」メソッドを呼び出しますか

  • いいえの場合-使用する最も簡単な方法は何ですか?

EDIT(4返信後)-すばらしい返信後の明確化の最後の質問-保持するように設定したカスタムオブジェクトのインスタンス変数/プロパティについてまだよくわかりませんか?これらは、カスタムオブジェクトクラスの「dealloc」メソッドを介してのみ解放されるようです。[スーパーリリース]とともに手動でこれを行います。

したがって、配列をクリアし直し、removeAllObjectsを実行してから、NSArrayがカスタムオブジェクトに「解放」を発行したが、「dealloc」を呼び出さなかった場合、インスタンス変数はどのように解放されますか?

15
Greg

removeAllObjectsは、配列からオブジェクトを削除します。このプロセスにより、オブジェクトにリリースメッセージが送信され、参照カウントが減少します。参照カウントがゼロに達すると、オブジェクトは割り当て解除されます。

リークするので、このようにしないでください。

NSObject *object = [[NSObject alloc] init];       + 1
[array addObject:object];                         + 1
[array removeAllObjects];                         - 1
                                                =======
                                                = + 1 -> Leak

これは正しい方法です:

NSObject *object = [[[NSObject alloc] init] autorelease]; + 1 (from alloc) - 1 (from autorelease)
[array addObject:object];                         + 1
[array removeAllObjects];                         - 1
                                                =======
                                                =   0 -> Object will be deallocated

RemoveAllObjectsを呼び出す代わりに、配列を解放することもできます。配列の割り当てが解除されると、その中にあるすべてのものが解放され、オブジェクトへの参照が他にない場合は、割り当てが解除されます。

33
Matthias Bauch

はい、removeAllObjectsを呼び出します。念のため、配列にオブジェクトを追加するとき、またはオブジェクトを含む配列を作成するときは、retainを呼び出さないでください。これは自動的に行われます。

deallocについても、これは自動的に行われ、いつ予測することはできません。

Deallocに必要なのは配列オブジェクト自体だけです。つまり、インスタンス変数またはivarであると想定しますか?

すべてが良好であることを確認するには、製品->分析を使用してアナライザーを実行します。そして、Leaksインストゥルメントを使用してInstrumentsでアプリにプロファイルを与え、コードがメモリリークを引き起こしていないことを確認します。

3
Max MacLeod

deallocメソッドが直接呼び出されることはありません。すべてがretain/releaseメカニズム(および参照カウントの原則)を介して行われます。つまり、これはreleaseメソッドではなく、直接呼び出されるdeallocです。 deallocメソッドは、最後のrelease呼び出しによってオブジェクトの参照カウント(retainCount)がゼロに達した場合にのみランタイムによって呼び出されます。つまり、オブジェクトは実際にはメモリから解放され、誰も使用しませんもう。

NSArrayおよびCocoaのすべてのコンテナークラス(NSDictionaryNSSet、...)は、それらの値を保持します。したがって、NSArrayのようなコンテナーにオブジェクトを追加すると、その値がretainになります。そして、その値を削除すると(removeAllObjectsを呼び出すときを含む)、それはreleaseになります。

メモリ管理のルールは簡単に実行できます。ただし、releaseautoreleaseを呼び出した場合は、allocまたはretainを呼び出すだけでよいという重要なルールがあります。またはcopyメソッド。これは常に、alloc/retain/copyrelease/autoreleaseを呼び出すようにしたオブジェクトの責任です。保留中のalloc/retain呼び出しなしでcopy/release/autoreleaseを残さないでください(そうしないと、リークが発生します) 、ただしrelease/autorelease/allocを自分で呼び出さなかった場合は、決してretain/copyを呼び出さないでください。

良い例1:

MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[obj release]; // this release balance the "alloc" on the first line, so that's good

[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. As nobody retains it anymore, its dealloc method will be called automatically.

良い例2:

MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. But your own code still retains a reference to it (because of the "alloc" on first line) so it won't be removed from memory right now
[obj release]; // this release balance the "alloc" on the first line, and as nobody retains the object anymore, its dealloc method will be called and it will be deallocated from memory

良い例3:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
// no need to call "release" here as there is no "alloc" done in the scope of this code

悪い例:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
[obj release]; // Crash here! obj does not exists anymore and has been deallocated from memory before this line!
1
AliSoftware

基本的にremoveAllObjectsメソッドはreleaseメッセージをすべてのオブジェクトに送信します。 releaseメソッドはオブジェクト参照カウントをデクリメントします =。また、オブジェクトの参照カウントが0に達すると、deallocメッセージがオブジェクトに送信されます。

あなたの質問に対する答えは、[array removeAllObjects]への電話は完全に安全です。ちなみに、配列が必要なくなった場合は、[array release]を直接呼び出すことができます。これにより、配列だけでなくそのすべてのオブジェクトが解放されます。

1
EmptyStack