web-dev-qa-db-ja.com

Objective Cのリリース、自動リリース、およびデータ型

私はメモリマネージコードを初めて使用しますが、アイデアはかなりよくわかります。

XCodeのリークツールを使用してアプリを実行すると、カスタムオブジェクトをクリーンアップするだけでよく、たとえば動的に作成された配列は不要なので、これらのデータ型は自動解放されると考えました-配列を解放するだけでよいので意味がありますそれらに(保持)があるプロパティとして使用しました。

それから私は何か奇妙なことに気づきました:このように初期化された特定の配列でリークが発生していました:

NSMutableArray *removals = [NSMutableArray new];

似たようなものではない

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

さて、「new」を設定した理由は、0〜99のアイテムが含まれる可能性があるためです。一方、私が知っていたもう1つは常に9になります。両方の配列が後でユーザーに基づいて同じメソッドに渡されるためインタラクションでは、メソッドの最後で解放しなかった場合はリークが発生していたか、解放した場合は例外でした!

最初の配列を

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

漏れはなく、何も放出する必要はありません。誰か説明できますか?

25
Michael

メモリ管理ルール に記載されているように、+alloc+new-copy、または-mutableCopyで作成したオブジェクトがある場合は常に、あなたはそれを所有し、ある時点でそれをリリースする責任があります。 (実際、 +new[[MyClass alloc] init]の省略形です。)既に述べたように、解放せずに[NSArray new]を介して配列を作成すると、メモリリークが発生します。ただし、このオブジェクトを適切に処理すると、通常、ある時点でそれを解放することができます。例えば:

  • が使用するメソッドの場合、配列はwithinから呼び出されます。アレイを作成すると、使用後にアレイを解放できるはずです。内部メソッドが配列へのより永続的な参照を保持する必要がある場合、そのメソッドは-retain、そして最終的には-releaseをオブジェクトに送信する責任があります。例えば:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • オブジェクトの-init methodで配列を作成した場合、-dealloc methodは、オブジェクトが破棄されたときにそれを解放できます。

  • 配列を作成してからメソッドからreturnする必要がある場合は、自動解放が発明された理由を発見しました。メソッドの呼び出し元は、+alloc+new-copy、または-mutableCopyメソッドではないため、オブジェクトを解放する必要はありませんが、最終的にリリースされることを確認します。この場合、オブジェクトを返す前に、オブジェクトで-autoreleaseを手動で呼び出します。例えば:

    - (NSArray *)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        return [removals autorelease];
    }
    

+arrayWithCapacity:を使用して配列を作成する場合、「特別な」メソッドの1つを呼び出すことはないため、結果を解放する必要はありません。これはおそらく上記の最後の例と同様に-autoreleaseで実装されますが、必ずしもそうとは限りません。 (偶然にも、空の自動解放されたNSMutableArrayを[NSMutableArray array]で作成することもできます。メソッドはNSArrayにあるため、NSMutableArrayのドキュメントには表示されませんが、NSMutableArrayに送信されると可変配列が作成されますクラス。)メソッドから配列を返す場合は、これを[[[NSMutableArray alloc] init] autorelease]の省略形として使用できますが、これは単なるショートカットです。ただし、多くの場合、-initまたは+newを使用してオブジェクトを作成し、適切なタイミングで手動で解放できます。

65
John Calsbeek

これは、舞台裏での実装方法です。

+(NSMutableArray*) new
{
    return [[NSMutableArray alloc] init];
}

そして

+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
    return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}

最初の場合、配列は割り当てられているだけで、割り当てを解除する必要があります。逆に、arrayWithCapacityは自動解放されているため、割り当て解除を忘れてもリークは発生しません。

7
Tuan

Cocoaは特定の命名規則を使用しています。 alloc、new、またはcopyで始まるものはすべて、retainCountが1の何かを返し、解放する必要があります。関数が返すその他のものはすべて、バランスのとれたretainCountを持っています(他の何かによって保持されているか、保持されて解放されている可能性があります)。

そう:

NSMutableArray *removals = [NSMutableArray new];

1のretainCountを持ち、そして:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

または

NSMutableArray *removals = [NSMutableArray array];

メソッドの前にalloc、new、copyが付いていないので、そうしないでください。これはすべてメモリ管理 documentation で詳しく説明されています。特に:

名前が「alloc」または「new」で始まるか「copy」を含むメソッド(たとえば、alloc、newObject、またはmutableCopy)を使用して作成した場合、または保持メッセージを送信した場合は、オブジェクトの所有権を取得します。リリースまたは自動解放を使用して、所有するオブジェクトの所有権を放棄する必要があります。それ以外の場合は、オブジェクトを解放してはなりません。

4
Louis Gerbarg