web-dev-qa-db-ja.com

通常、Objective-Cデリゲートに、保持ではなくプロパティが割り当てられるのはなぜですか?

スコットスティーブンソンが管理している素晴らしいブログを閲覧しており、デリゲートに「assign」プロパティと「retain」を割り当てるという基本的なObjective-Cの概念を理解しようとしています。ガベージコレクション環境では両方が同じであることに注意してください。私は主に非GCベースの環境(例:iPhone)に関心があります。

スコットのブログから直接:

「assignキーワードは、値をコピーまたは保持するのではなく、インスタンス変数に直接割り当てるセッターを生成します。これは、NSIntegerやCGFloatなどのプリミティブ型、またはデリゲートなど、直接所有していないオブジェクトに最適です。」

デリゲートオブジェクトを直接所有していないということはどういう意味ですか?私は通常、代理人を保持します。なぜなら、彼らが奈落の底に行きたくない場合、保持は私のためにそれを世話します。私は通常、それぞれのdataSourceとデリゲートからUITableViewControllerを抽象化します。その特定のオブジェクトも保持します。私のUITableViewが常にそのデリゲートを持っているように、それが消えないことを確認したいです。

誰かがどこで/なぜ間違っているのかをさらに説明できますか?そのため、Objective-C 2.0プログラミングのこの一般的なパラダイムを保持する代わりにデリゲートでassignプロパティを使用することを理解できますか?

ありがとう!

176
anon

デリゲートの保持を回避する理由は、保持サイクルを回避する必要があるためです。

AはBを作成しますAはBのデリゲートとして自身を設定します…Aはその所有者によって解放されます

BがAを保持していた場合、BはAを所有しているため、Aは解放されないため、Aのdeallocは呼び出されず、AとBの両方がリークします。

AがBを所有し、deallocでそれを取り除くため、Aがなくなることを心配する必要はありません。

175
Andrew Pouliot

デリゲートメッセージを送信するオブジェクトはデリゲートを所有していないためです。

多くの場合、コントローラがビューまたはウィンドウのデリゲートとしてそれ自体を設定する場合、コントローラはビ​​ュー/ウィンドウを所有するため、ビュー/ウィンドウがそのデリゲートを所有する場合、両方のオブジェクトが互いに所有します。もちろん、これは保持サイクルであり、同じ結果を伴うリークに似ています(死んでいるはずのオブジェクトは生きたままです)。

また、オブジェクトがピアである場合もあります。どちらももう一方を所有していないのは、おそらく両方が同じ3番目のオブジェクトによって所有されているためです。

いずれにしても、デリゲートを持つオブジェクトはそのデリゲートを保持するべきではありません。

(ちなみに、少なくとも1つの例外があります。それが何であったかは覚えていませんし、それには正当な理由があるとは思いません。)


補足(2012-05-19に追加):ARCでは、weakの代わりにassignを使用する必要があります。弱い参照は、オブジェクトが終了すると自動的にnilに設定され、委任オブジェクトがデッドデリゲートにメッセージを送信する可能性を排除します。

何らかの理由でARCから離れる場合は、少なくともオブジェクトを指すassignプロパティをunsafe_unretained。これは、オブジェクトへの保持されていないがゼロ以外の参照であることを明示します。

assignは、ARCとMRCの両方の非オブジェクト値に適切なままです。

44
Peter Hosey

割り当てるデリゲートがある場合、オブジェクトが割り当て解除されるときは常にそのデリゲート値を常にnilに設定することが非常に重要であることに注意してください。他の場所でそうします。

その背後にある理由の1つは、保持サイクルを回避することです。 AとBの両方のオブジェクトが相互に参照し、いずれもメモリから解放されないというシナリオを避けるためです。

Acutally assignは、NSIntegerやCGFloatなどのプリミティブ型、またはデリゲートなど、直接所有していないオブジェクトに最適です。

1
Puneet Sharma