13

これが私が参照しているコードです。

// Person.h

@interface Person : NSObject {
    NSString *firstName;
    NSString *lastName;
}
@end

// Person.m

@implementation Person
- (id)init {
    if (![super init]) return nil;
    firstName = @"John";
    lastName = @"Doe";
}
@end

// MyClass.m

@implementation MyClass
    .....
- (NSArray *)getPeople {
    NSMutableArray *array = [[NSMutableArray alloc] init];

    int i;
    for (i = 0; i < 10; i++) {
        Person *p = [[Person alloc] init];
        [array addObject:p];
    }

    return array;
}
    .....
@end

これで、このサンプル コードではメモリ管理が行われていないことがわかりました。何が必要ですか?

getPeople ループでは、Person (retainCount 1) を割り当て、それを配列に追加しています。リテイン回数が2回になりましたよね?2 の場合、配列に追加した後に [p release] して、retainCount を 1 に戻す必要がありますか?

メソッドによって返された配列を解放するのは呼び出し元の責任であるという点で、私は正しいですか? (カウントが 1 であると仮定すると、Person のメモリとそのインスタンス変数も解放されます)。

Apple のメモリ管理に関するドキュメントを読みましたが、最も不明な点は、オブジェクトの保持カウントが増加することでしょうか? 誰がリリースする責任があるのか​​という考えは理解できたと思いますが。Apple によると、これが基本的なルールです。

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

bobDevil の文「アイテムに明示的に追加する保持カウントについてのみ心配する」という文は、私にぴったりでした。Apple の所有権ポリシーを読んだ後、基本的には、新しいオブジェクトを作成したオブジェクト/メソッドが、そのオブジェクトへの関心を解放する責任を負います。これは正しいです?

ここで、オブジェクトを受け取り、それをインスタンス変数に割り当てるメソッドがあるとします。まだ興味があるので、受け取ったオブジェクトを正しく保持する必要がありますか?

これのいずれかが正しくない場合は、お知らせください。

4

3 に答える 3

19

配列に追加した後、保持カウントが2であることは正しいです。ただし、アイテムに明示的に追加する保持カウントだけを気にする必要があります。

オブジェクトを保持することは、「私はあなたとの関係が終わっていないので、立ち去らないでください」という契約です。基本的な経験則 (例外はありますが、通常は文書化されています) は、オブジェクトを割り当てたり、コピーを作成したりするときに、オブジェクトを所有することです。これは、オブジェクトの保持カウントが 1 である (自動解放されていない) ことを意味します。これらの 2 つのケースでは、作業が完了したらリリースする必要があります。さらに、オブジェクトを明示的に保持する場合は、それを解放する必要があります。

したがって、あなたの例に具体的に言うと、Person を作成するときに、1 つの保持カウントがあります。あなたはそれを配列に追加し(それで何でもします、気にしません)、それから Person で終わったので、それを解放します:

Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it

また、上で述べたように、一般に alloc または copy 中にのみオブジェクトを所有するため、反対側のそれと一貫性を保つために、getPeople メソッドの呼び出し元がそれを所有しないように、自動解放された配列を返す必要があります。 .

return [array autorelease];

編集:正解です。作成した場合は、リリースする必要があります。(保持を通じて)それに関心を投資する場合は、それをリリースする必要があります。

于 2009-07-25T03:00:51.837 に答える
5

alloc を明示的に呼び出すと保持カウントが増加するため、明示的に解放する必要があります。

ファクトリ メソッドは、通常、自動解放されたオブジェクトを提供します ([NSMutableArray 配列] など。これを長期間維持するには、これを明確に保持する必要があります)。

NSArray と NSMutableArray addObject: に関しては、他の誰かがコメントする必要があります。クラスが独自のメモリ管理を設計パターンとしてどのように処理するかという点で、クラスをブラックボックスとして扱っていると思います。そのため、NSArray に渡したものを明示的に解放することは決してありません。破棄されると、保持カウント自体のデクリメントを処理することになっています。

ivar を @property (retain) suchAndSuchIvar のようなプロパティとして宣言し、実装で @synthesize を使用すると、やや暗黙的な保持を取得することもできます。Synthesize は基本的に setter と getter を作成します。具体的に呼び出す (retain) と、setter は渡されたオブジェクトを保持します。セッターは次のように構成できるため、すぐにわかるとは限りません。

Person fart = [[Person alloc] init];
fart.firstName = @"Josh"; // this is actually a setter, not accessing the ivar
                          // equivalent to [fart setFirstName: @"Josh"], such that
                          // retainCount++

編集:

そして、メモリ管理に関しては、オブジェクトを配列に追加するとすぐに、それで完了です...だから:

   for (i = 0; i < 10; i++) {
       Person *p = [[Person alloc] init];
       [array addObject:p];
       [p release];
   }

ジョシュ

于 2009-07-25T02:44:15.903 に答える
2

通常、保持カウントについて心配する/しない/必要があります。それは内部的に実装されています。オブジェクトを保持することによってオブジェクトを「所有」するかどうかだけを気にする必要があります。上記のコードでは、あなたではなく、配列がオブジェクトを所有する必要があります (ループの外では、配列を介する場合を除き、オブジェクトへの参照すらありません)。を所有[[Person alloc] init]しているため、リリースする必要があります。

したがって

Person *p = [[Person alloc] init];
[array addObject:p];
[p release];

また、「getPeople」の呼び出し元が配列を所有するべきではありません。これがコンベンションです。最初に自動解放する必要があります。

NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];

メモリ管理に関する Apple のドキュメントを参照してください: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

于 2009-07-25T02:51:51.087 に答える