25

私はメモリ管理されたコードは初めてですが、アイデアはかなりよくわかります。

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

次に、何か奇妙なことに気付きました。次のように初期化された特定の配列でリークが発生していました。

NSMutableArray *removals = [NSMutableArray new];

しかし似たようなものではない

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

さて、一方が「新規」で設定された理由は、0 ~ 99 の項目を含めることができるためです。一方、私が知っていたもう一方の項目は常に 9 であることがわかっていました。両方の配列が後でユーザーに基づいて同じメソッドに渡されるためです。メソッドの最後で解放しなかった場合はリークが発生し、解放した場合は例外が発生しました。

最初の配列を次のように変更しました

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

リークは発生せず、何もリリースする必要はありません。誰でも説明できますか?

4

3 に答える 3

65

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

  • 配列を使用するメソッドが、配列を作成するメソッドから呼び出された場合、使用後に配列を解放できるはずです。内部メソッドが配列へのより永続的な参照を保持する必要がある場合、そのメソッドはオブジェクトへの送信-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 を で作成することもできます[NSMutableArray array]。メソッドは NSArray にあるため、NSMutableArray の下のドキュメントには表示されませんが、NSMutableArray クラスに送信されると可変配列が作成されます。)メソッドから配列を返す場合、これを省略形として使用できますが、[[[NSMutableArray alloc] init] autorelease]これは単なる省略形です。ただし、多くの場合、-initまたは+newを使用してオブジェクトを作成し、適切なタイミングで手動でリリースできます。

于 2009-08-02T21:20:03.790 に答える
7

これは、舞台裏で物事がどのように実装されているかです:

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

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

最初のケースでは、配列は割り当てられているだけで、割り当てを解除する責任があります。逆に、arrayWithCapacity は自動解放されており、割り当て解除を忘れてもリークは発生しません。

于 2011-04-22T09:35:53.840 に答える
4

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

それで:

NSMutableArray *removals = [NSMutableArray new];

保持カウントは1で、次のようになります。

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

また

NSMutableArray *removals = [NSMutableArray array];

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

名前が「alloc」または「new」で始まるメソッドまたは「copy」を含むメソッド(alloc、newObject、mutableCopyなど)を使用してオブジェクトを作成する場合、またはオブジェクトに保持メッセージを送信する場合は、オブジェクトの所有権を取得します。リリースまたは自動リリースを使用して、所有するオブジェクトの所有権を放棄するのはユーザーの責任です。オブジェクトを受け取ったときは、それを解放してはなりません。

于 2009-08-02T19:21:14.607 に答える