Objective Cのリリース、自動リリース、およびデータ型
-
10-07-2019 - |
質問
メモリマネージコードは初めてですが、アイデアはかなりよくわかります。
XCodeのリークツールを介してアプリを実行すると、カスタムオブジェクトのみをクリーンアップする必要があることに気付きましたが、たとえば動的に作成された配列はそうではないため、これらのデータ型は自動解放されると考えました-必要なのは理にかなっています(保持する)プロパティとして使用した配列を解放します。
その後、奇妙なことに気付きました:このように初期化された特定の配列でリークが発生していました:
NSMutableArray *removals = [NSMutableArray new];
しかし似たものではない
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];
今、「新規」でセットアップされた理由私が知っている他の1つは常に9であるのに対し、0から99のアイテムを含めることができるということです。両方の配列は後でユーザーの操作に基づいて同じメソッドに渡されるため、そうしないとリークが発生しましたメソッドの最後にリリース、または私がやった場合は例外!
最初の配列を次のように変更しました
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];
そして、私はリークを取得せず、何もリリースする必要はありません。誰でも説明できますか?
解決
メモリ管理ルール、 + alloc
、 + new
、 -copy
、または -mutableCopyで作成したオブジェクトがある場合
、あなたはそれを所有し、ある時点でそれをリリースする責任があります。 (実際、 + new
は、 [[MyClass alloc] init]
の短縮形です。 [NSArray new]
をリリースしないと、メモリリークが発生します。ただし、このオブジェクトを適切に処理すれば、通常はある時点で解放することができます。例:
-
配列を作成するメソッドの内から配列を使用するメソッドが呼び出された場合、配列を解放した後、配列を解放できるはずです使用されました。内部メソッドが配列へのより永続的な参照を保持する必要がある場合、そのメソッドは
-retain
を送信し、最終的には-release
をオブジェクトに送信します。例:- (void)myMethod { NSArray *removals = [NSArray new]; // ... [someObject someOtherMethod:removals]; [removals release]; }
-
オブジェクトの
-init
メソッドで配列を作成した場合、-dealloc
メソッドはオブジェクトが破棄されたときに解放できます。 -
配列を作成し、メソッドから返す必要がある場合、自動解放が発明された理由を発見しました。メソッドの呼び出し元は、
+ alloc
、+ new
、-copy
ではないため、オブジェクトを解放する責任はありません。または-mutableCopy
メソッドですが、最終的にリリースされることを確認する必要があります。この場合、オブジェクトを返す前に、オブジェクトに対して-autorelease
を手動で呼び出します。例:- (NSArray *)myMethod { NSArray *removals = [NSArray new]; // ... return [removals autorelease]; }
+ arrayWithCapacity:
で配列を作成する場合、「特別」のいずれかを呼び出していません。メソッドなので、結果をリリースする必要はありません。これはおそらく、上記の最後の例のように -autorelease
で実装されますが、必ずしもそうではありません。 (ちなみに、 [NSMutableArray array]
で空の自動解放されたNSMutableArrayを作成することもできます。このメソッドはNSArrayにあるため、NSMutableArrayの下のドキュメントには表示されませんが、変更可能になりますNSMutableArrayクラスに送信されたときの配列。)メソッドから配列を返す場合は、これを [[[NSMutableArray alloc] init] autorelease]
の省略形として使用できますが、単なるショートカットです。ただし、多くの場合、 -init
または + new
を使用してオブジェクトを作成し、適切なタイミングで手動でリリースできます。
他のヒント
これは、物事が舞台裏で実装される方法です。
+(NSMutableArray*) new
{
return [[NSMutableArray alloc] init];
}
and
+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}
最初のケースでは、配列のみが割り当てられ、割り当て解除の責任はユーザーにあります。それどころか、arrayWithCapacityは自動的に解放され、割り当て解除を忘れてもリークは発生しません。
Cocoaは、特定の命名規則を使用しています。 alloc、new、またはcopyで始まるものはすべて、retainCountが1の何かを返し、解放する必要があります。関数が返す他のものはすべて、バランスの取れたretainCountを持ちます(他の何かによって保持されるか、保持されて解放される可能性があります)。
だから:
NSMutableArray *removals = [NSMutableArray new];
retainCountが1で、かつ:
NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];
または
NSMutableArray *removals = [NSMutableArray array];
メソッドにはalloc、new、copyのプレフィックスが付いていないためこれはすべてメモリ管理ドキュメント。特に:
次の場合、オブジェクトの所有権を取得します 名前を持つメソッドを使用して作成します “ alloc”で始まりますまたは“ new”または 含まれています“コピー” (たとえば、alloc、 newObject、またはmutableCopy)、または 保持メッセージを送信します。あなたは 放棄の責任 所有しているオブジェクトの所有権 リリースまたは自動リリース。それ以外の時間 あなたは物を受け取ります、あなたはしてはいけません リリースします。