0

getter/setter を作成する NSArray のプロパティを作成しました。init メソッドと dealloc メソッドでインスタンス変数を使用することを Apple が推奨していることは知っています。次のコードで何をすべきかを理解しようとしています。

(1) 追加のリリース ステートメントが必要ですか? 配列の保持カウントが 2 ではなく、dealloc で 1 になると、リークが残ります。または、自動リリースがこれを処理しますか?

(2)xCodeまたはinstrumentsに特定の変数を追跡して、プロセスを通過する保持カウントを確認する方法はありますか。

@property (nonatomic, retain) NSArray *array;

@synthesize arrary = _array;

- (id)initWithNibName:(NSString *)nibNameOrNil 
               bundle:(NSBundle *)nibBundleOrNil 
        initWithArray:(NSArray *)array
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

        _array = [[NSArray alloc] initWithArray:array];

    }
    return self;
}

- (void)dealloc
{
    [_array release];

    [super dealloc];
}
4

3 に答える 3

2

(1) 追加のリリース ステートメントが必要ですか? 配列の保持カウントが 2 ではなく、dealloc で 1 になると、リークが残ります。または、自動リリースがこれを処理しますか?

これをステップスルーしましょう:

@property (nonatomic, retain) NSArray *array;

// The setter in this case will do the proper ref counting:
@synthesize arrary = _array;

- (id)initWithNibName:(NSString *)nibNameOrNil 
               bundle:(NSBundle *)nibBundleOrNil 
        initWithArray:(NSArray *)array
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // _array is nil at allocation
        _array = [[NSArray alloc] initWithArray:array]; // << self holds one reference

    }
    return self;
}

- (void)dealloc
{
    [_array release];  // << self holds zero references
    [super dealloc];
}

つまり、これ以上必要なものはありません。個人的にはcopy、イニシャライザとプロパティに対してのみ使用します ( とは対照的にretain)。

(2)xCodeまたはinstrumentsに特定の変数を追跡して、プロセスを通過する保持カウントを確認する方法はありますか。

はい。ただし、いくつかのランタイム ショートカットとこれには例外があります。

最も簡単な方法は、allocation インストゥルメントを使用してインストゥルメントを実行し、参照カウントの記録を有効にすることです。次に、個々のオブジェクトのすべての参照カウントのバックトレースと時間を記録します。

于 2012-04-13T05:12:21.147 に答える
0
  1. あなたのコードは私には大丈夫に見えます。追加のリリースを追加する必要はありません。initメソッドでは、_arrayの保持カウントは1です。deallocでリリースした後、ポインターがぶら下がらないように、_array=nilを実行する必要があります。

  2. リークをチェックするには、次のいずれかまたは両方を実行できます。

(i)CMD + Shift + B --->これは、コードに対して分析を実行して、このような問題を特定します。

(ii)「機器」の「リーク」および「割り当て」ツールを使用します。ここでは、実行中にアプリケーションが持つ割り当てとリーク(存在する場合)を監視できます。非常に便利で、「分析」では捕まえられないものを捕まえることもあります。

于 2012-04-12T03:37:07.050 に答える
0

編集: Apple の推奨事項に準拠するように変更されました。この回答に続くコメントは、私の元の (そして非常に悪い) バージョンを参照しています。今後は、iOS Developer Library のPractical Memory Managementに適切な注意を払います。

質問 (1) : いいえ、余分なリリースは必要ありません。の後[[ASArray alloc] initWithArray:array]、アレイの保持カウントは になり1ます。ではdealloc、 を呼び出すと[_array release]が返されるため0、解放する必要があります。

その間に が呼び出された場合、新しいオブジェクトを保持し、古いオブジェクト解放することによって[setArray:]、そのプロパティ宣言に従います。retain

他のオブジェクトまたはメソッドが配列を保持している場合、それを解放するのは彼らの責任です。配列のretainCountが1開始時よりも大きい場合dealloc、他のオブジェクトが少なくとも一時的にそれを保持しています。

質問 (2) :retainCount実行時に確認できますが、NSObject プロトコル リファレンスが警告しているように、オブジェクトが複数の自動解放プールに入ってしまい、そのカウントが無意味に高くなりがちです。

おまけ[[NSArray alloc] initWithArray:array]:入力の保持カウントを使用して追加することを考えているかもしれません1。これは、不変ソースへの参照を保持して渡すことによって「コピー」が作成された場合にのみ発生します。この場合、他のオブジェクトもそのソースへの参照を保持しています。 [[NSString alloc] initWithString:]そのソースが不変であるかどうかを検出し、これを行います。[[NSArray alloc] initWithArray:]ではない。 [NSArray copy]一方、それ自体を保持して返します。

もちろん、これらの最適化は実装固有のものであり、決して想定すべきではありません。ただし、次のように、いくつかのオブジェクトを構築し、自動解放を回避し、それらのアドレスとretainCountsに従うことは教育的です。

NSArray *array1 = [[NSArray alloc] initWithObjects:@"a", nil];
// Do not just assign array1 to [[NSArray alloc] init], or you'll get a singleton empty array with a high retain count.
// Make array1 mutable, and array2 should be copied differently.
NSLog(@"Constructed array1");
NSLog(@"array1 address = %p retainCount = %d", array1, [array1 retainCount]);
NSArray *array2 = [array1 copy];
// Use [[NSArray alloc] initWithArray:] and the results may be different.
NSLog(@"Constructed array2");
NSLog(@"array1 address = %p retainCount = %d", array1, [array1 retainCount]);
NSLog(@"array2 address = %p retainCount = %d", array2, [array2 retainCount]);
[array1 release];
NSLog(@"Released array1");
NSLog(@"array2 address = %p retainCount = %d", array2, [array2 retainCount]);
[array2 release];
于 2012-04-12T01:50:46.753 に答える