LoginSignup
258
242

More than 5 years have passed since last update.

Swiftの循環参照問題におけるunownedとweakの使い分けについて

Last updated at Posted at 2014-08-24

はじめに

前回の記事 Swiftのクロージャにおける循環参照問題でunownedとweakの使い分けがわからない にて、unownedとweakの使い分けがわからない旨を記載したところ、多くの方よりコメント欄で助言を頂いたので、その内容を踏まえてこちらに新たに記事として記載しました。コメントをくださった皆様ありがとうございました。ご指摘がありましたらコメントにてお寄せください。

補足

こちらにまとめる情報は私の個人的な見解によるまとめです。コメント欄に助言頂いた方の総意ではないので、前回の記事のコメント欄も合わせてご参照頂くことをお薦めします。本来なら前回の記事に追記すべきですが、新規で読まれた方が追記だらけで読みにくくなりそうなので記事を分けさせてもらいました。

unownedとweakの使い分けの判断

項番 循環参照 対象の変数をweakで対応し
実行時に変数がnilになる可能性
対応
#1 しない --- unowned、weakは記述しない
対象の変数は強参照扱い (strong)
#2 する あり weakを記述する
#3 する なし 1.weakを記述する
2.unownedを記述する
weakとunownedのどちらで記述するかはエンジニアの判断

循環参照するか、しないかの切り分け

循環参照するか、しないかの切り分けはエンジニアが考慮する必要があります。この切り分けはObjCと同様なので、ここでは詳細には触れません。

ちなみに、Xcode6 Beta5のSwiftではコンパイルワーニングで循環参照を知らせてくれません。とはいえ循環参照のコンパイルワーニングはObjCでも全部網羅されていないので、最終的にはエンジニアが考慮する必要があるのはかわらないのですが。

対象の変数をweakで対応し、実行時に変数がnilになる可能性の切り分け

そもそも、実行時に循環参照する対象の変数がnilになる可能性で判断ではなく、対象の変数定義がOptional定義かどうかで判断できないか

常にOptional定義かどうかで判断できないのではと思っています。例えばselfself!としてunwrapしてアクセスしないので、selfはOptionalではないと思いますが、非同期のコールバックや遅延実行を絡めたクロージャではselfが先に解放される場合があります。これは変数にnilが代入されたというよりも、変数が存在しなくなったのでnilと同義になったと言えるのではと思います。つまり、変数にnilが代入されるということと、変数が解放されnilになるのは同じnilの状態ですが区別する必要があり、この両方の遷移によるnilを考慮した対応をする必要があるためOptional定義だけで判断するのは片手落ちになってしまうと思います。

よって、weakとunownedの判断は循環参照する対象の変数がnilになるのかどうかをケースバイケースで考慮する必要があります。これはObjCのころのBlockにおける循環参照の対象となる変数がnilになる可能性を考慮する問題と同じです。

weakとunownedのどちらで記述するかの判断

weakとunownedのどちらで記述するかはエンジニアの判断によりますが、『実行時に対象の変数がnilになる可能性の切り分け」が難しい部分もあるので、エンジニアの熟練度やチームでの合意に応じてポリシーを決めればよいのではと思います。よって、どちらが正しいと言うものでもないと思っています。

引用項番 ケース 参照方式 メリット デメリット
#3-1. weak 弱参照 循環参照の場合、常にこの記述方法で対応できる 合わせてif letでunwrapの記述が常に必要
unownedで記述できる場合はunwrapの記述が冗長になる
#3-2. unowned 弱参照 クロージャ内で対象の変数がnilにならないことを明記できる
unwrapの記述が不要
対象の変数がnilだった場合にクラッシュする

AppleのSwiftドキュメントでは?

The Swift Programming Language - Automatic Reference Counting -
Resolving Strong Reference Cycles Between Class Instances

Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.

The Swift Programming Language - Automatic Reference Counting - Unowned References

If you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error. Use unowned references only when you are sure that the reference will always refer to an instance.

Note also that Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so.

助言くださった方

助言くださった皆様ありがとうございます。(コメント順)

修正 8月27日 23時

誤解を招く言葉足らずのところを修正しました。
循環参照の対象の変数はstrongでキャプチャしているので、nilになることはありません。
ここでいう実行時に対象の変数がnilになる可能性とは、循環参照の変数をweakで扱った場合です。

【修正前】実行時に対象の変数がnilになる可能性の切り分け

【修正後】対象の変数をweakで対応し、実行時に変数がnilになる可能性の切り分け

258
242
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
258
242