2

ブロック/ARC のリテイン サイクルの問題に取り組んでおり、ニュアンスを理解しようとしています。任意のガイダンスをいただければ幸いです。

「ブロックと変数」に関する Apple のドキュメント (http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html) には、次のように記載されています。

メソッドの実装内でブロックを使用する場合、オブジェクト インスタンス変数のメモリ管理のルールはより微妙になります。

参照によってインスタンス変数にアクセスする場合、self は保持されます。インスタンス変数に値でアクセスすると、変数は保持されます。次の例は、2 つの異なる状況を示しています。

dispatch_async(queue, ^{
    // instanceVariable is used by reference, self is retained
    doSomethingWithObject(instanceVariable);
});


id localVariable = instanceVariable;
dispatch_async(queue, ^{
    // localVariable is used by value, localVariable is retained (not self)
    doSomethingWithObject(localVariable);
});

この説明はわかりにくいと思います。

  1. これは「値による」/「参照による」用語の適切な使用ですか? これらの変数が同じタイプ (id) であると仮定すると、それらを区別する特徴はスコープにあるようです。
  2. 「参照」の例で自己がどのように参照されているかわかりませんか? アクセサー メソッドが使用されている場合 (例: 以下)、self が保持されていることがわかります。

    doSomethingWithObject(self.instanceVariable);

  3. 物事をどのような方法でやりたいかについてのガイダンスはありますか?

  4. 「値渡し」変数を利用するのが従来の知恵である場合、追加の変数宣言のために多くの追加コードが必要になるように思われますか?
  5. 入れ子になったブロックが登場する状況では、意図せずに保持されたオブジェクトのポプリが最終的に発生する可能性があるため、ブロックを相互に宣言することを避ける方が保守しやすいように思われますか?
4

2 に答える 2

4

instanceVariable書くことと同等に使う場合を考えてみてくださいself->instanceVariable。インスタンス変数は、定義上、オブジェクトに「添付」されself、自己オブジェクトが存在する間存在します。

instanceVariable(または)を使用self->instanceVariableすると、自分自身のアドレスから開始し、インスタンス変数 (selfオブジェクトの元のアドレスからの数バイトのオフセット) を要求することを意味します。

UsinglocalVariableはそれ自体が変数であり、self に依存せず、別のオブジェクトに関連するアドレスではありません。

ブロックは作成時に変数をキャプチャするため、通常、「ブロックが実行されたときにインスタンス変数の値を取得したい」という意味でインスタンス変数を使用することを好みますself。その時点でのインスタンス変数の値 (を呼び出すのとまったく同じ方法[self someIVarAccessorMethod])。ただし、いくつかの保持サイクルを作成しないように注意してください。

一方、 を使用するlocalVariableと、ローカル変数 (および ではなくself) はブロック作成時にキャプチャされるため、ブロック作成後にローカル変数が変更されても、ブロック内では古い値が使用されます。

// Imagine instanceVariable being an ivar of type NSString
// And property being a @property of type NSString too
instanceVariable = @"ivar-before";
self.property = @"prop-before";
NSString* localVariable = @"locvar-before";

// When creating the block, self will be retained both because the block uses instanceVariable and self.property
// And localVariable will be retained too as it is used directly
dispatch_block_t block = ^{
  NSLog(@"instance variable = %@", instanceVariable);
  NSLog(@"property = %@", self.property);
  NSLog(@"local variable = %@", localVariable);
};

// Modify some values after the block creation but before execution
instanceVariable = @"ivar-after";
self.property = @"prop-after";
localVariable = @"locvar-after";

// Execute the block
block();

その例では、出力は と がオブジェクトを介してアクセスされることを示しているinstanceVariableためself.propertyselfself は保持されましたが、instanceVariableとの値self.propertyはブロックのコードで照会され、実行時にそれぞれ"ivar-after"との値が返され"prop-after"ます。一方、localVariableはブロックが作成された時点で保持され、その値はその時点で const コピーされていたため、最後NSLogは が表示され"locvar-before"ます。

selfインスタンス変数やプロパティを使用したり、ブロックのコードで自分自身のメソッドを呼び出したりすると保持されます。ローカル変数は、ブロックのコードで直接使用すると保持されます。

注: このテーマについて説明している WWDC'11 および WWDC'12 のビデオを見ることをお勧めします。これらは非常に有益です。

于 2012-09-05T19:45:18.303 に答える
3
  1. これは「値による」/「参照による」用語の適切な使用ですか? 少なくとも典型的な使用法に似ています。値をローカル変数にコピーすることは、値をスタックにコピーすることに似ています。ivar を使用することは、別の場所に格納されている値へのポインターを渡すようなものです。

  2. 「参照」の例で自己がどのように参照されているかわかりませんか? メソッド内でインスタンス変数を使用すると、への参照selfが暗示されます。一部の人々であることを思い出すためだけに、ivar にアクセスするself->foo代わりに。私はそれをお勧めしませんが、ポイントはそれで、同じことをブロック内の ivar にアクセスすると、ブロックの期間中 ivar が確実に保持されるように が保持されます。foofoofooself->fooself

  3. 物事をどのような方法でやりたいかについてのガイダンスはありますか? ここでは、参照による受け渡しと値による受け渡しの区別について考えると便利です。AliSoftware が説明したように、関数が呼び出されたときに値で渡されたパラメーターがコピーされるのと同じように、ブロックの作成時にローカル変数が保持されます。ivar は、参照によって渡されたパラメーターがポインターを介してアクセスされるのと同じように、self を介してアクセスされるため、実際に使用するまでその値は決定されません。

  4. これにより、追加の変数宣言のために多くの追加コードが発生するように見えますか? ブロックはしばらく前からこの言語の機能でしたが、これが問題であることに気づいていませんでした。多くの場合、逆の動作が必要になります。つまり、1 つのブロック (または複数のブロック) 内で変更できる、ローカルで宣言された変数です。ストレージタイプはそれ__blockを可能にします。

  5. 意図せずに保持されたオブジェクトのポプリで最終的に終わる可能性があるため、互いの内部でブロックを宣言することを避ける方が保守しやすいように思えますか? 1 つまたは複数のブロックが必要な限りオブジェクトを保持できるようにしても問題はありません。オブジェクトは、それを使用するブロックが終了するとすぐに解放されます。これは、すべてのオブジェクトが自身の保持のバランスを取ることだけを心配する、通常の Objective-c の手動メモリ管理哲学に完全に適合します。ネストされたブロックの複数の層を避けるより良い理由は、そのようなコードは必要以上に理解するのが難しいかもしれないということです。

于 2012-09-06T05:33:41.673 に答える