スウィフトは持っています:
所有されていない参照は弱い参照とどう違うのですか?
所有されていない参照を使用しても安全なのはいつですか。
所有されていない参照は、C/C++では ぶら下がりポインタ のようなセキュリティ上のリスクがありますか?
weak
とunowned
の両方の参照は、参照先のオブジェクトにstrong
の保留を作成しません(別名、ARCが参照先のオブジェクトの割り当てを解除するのを防ぐために保持数を増やすことはありません)。
しかし、なぜ2つのキーワードがあるのでしょうか。この区別はOptional
型がSwift言語に組み込まれているという事実と関係があります。これらについての短い話: オプション型 はメモリの安全性を提供します(これは Swiftのコンストラクタ規則 で美しく機能します)。この利益を提供します)。
weak
参照はそれの可否をnil
にすることを可能にします(これは参照されたオブジェクトが割り当て解除されるときに自動的に起こります)、したがってあなたのプロパティの型はオプションでなければなりません。基本的に、コンパイラは安全なコードを書くことを可能な限り強制します。
unowned
参照は、その存続期間中に決してnil
にならないことを前提としています。所有されていない参照は初期化中に設定されなければなりません - これは参照がチェックなしで安全に使用できる非オプションの型として定義されることを意味します。何らかの理由で参照されているオブジェクトの割り当てが解除された場合、所有されていない参照が使用されるとアプリはクラッシュします。
アップルのドキュメント より:
その参照がその存続期間中のある時点でゼロになるのが有効であるときはいつでも弱い参照を使用してください。逆に、初期化中に設定された参照がnilにならないことがわかっている場合は、所有されていない参照を使用してください。
文書には、保持サイクルとそれらをどのように破るかを論じるいくつかの例があります。これらの例はすべて docs から抽出されたものです。
weak
キーワードの例:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person?
}
そして今、いくつかのASCIIアートのために(あなたは行くべきです ドキュメント を見てください - 彼らはきれいな図を持っています):
Person ===(strong)==> Apartment
Person <==(weak)===== Apartment
Person
およびApartment
の例は、2つのプロパティー(どちらもnilにすることが許可されている)が、強い参照サイクルを引き起こす可能性がある状況を示しています。このシナリオは弱い参照で最もよく解決されます。どちらのエンティティも、他に依存することなく存在できます。
unowned
キーワードの例:
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}
この例では、Customer
はCreditCard
を持っていてもいなくてもかまいませんが、CreditCard
は常にがCustomer
に関連付けられます。これを表すために、Customer
クラスにはオプションのcard
プロパティがありますが、CreditCard
クラスにはオプションではない(そして所有されていない)customer
プロパティがあります。
Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard
Customer
およびCreditCard
の例は、1つのnilにすることが許可されているプロパティと、nilにすることができない別のプロパティが、強い参照サイクルを引き起こす可能性がある状況を示しています。このシナリオは、所有されていない参照で最もよく解決されます。
アップルからのメモ:
弱い参照は、それらの値が実行時に変わる可能性があることを示すために、変数として宣言する必要があります。弱い参照は定数として宣言できません。
両方のプロパティが常に値を持つべきで、初期化が完了するとどちらのプロパティもnilになるべきではないという3番目のシナリオもあります。
また、クロージャを扱うときに避けるべき古典的な保持サイクルのシナリオもあります。
このために、私はあなたが アップルのドキュメント を訪れるか、あるいはこの本を読む ことをお勧めします 。
Q1。 「所有されていない参照」と「弱い参照」はどう違うのですか?
弱い参照:
弱い参照は、それが参照するインスタンスを強く保持しない参照であり、ARCが参照先のインスタンスを破棄しないようにするためのものではありません。弱参照は「値なし」を持つことが許可されているため、すべての弱参照はオプションの型を持つものとして宣言する必要があります。 (アップルドキュメント)
未所有の参考資料:
弱い参照のように、所有されていない参照は、それが参照するインスタンスを強く保持しません。弱い参照とは異なり、所有されていない参照は常に値を持つと見なされます。このため、所有されていない参照は常に非オプション型として定義されます。 (アップルドキュメント)
それぞれを使用する場合
その参照がその存続期間中のある時点でゼロになるのが有効であるときはいつでも弱い参照を使用してください。逆に、初期化中に設定された参照がnilにならないことがわかっている場合は、所有されていない参照を使用してください。 (アップルドキュメント)
Q2。 「未所有の参照」を使用しても安全なのはいつですか?
上記のように、所有されていない参照は常に値を持つと見なされます。そのため、参照がゼロにならないことが確実な場合にのみ使用してください。次の例を通じて、Apple Docsは所有されていない参照のユースケースを説明しています。
2つのクラスCustomer
とCreditCard
があるとします。顧客はクレジットカードなしで存在することができるが、クレジットカードは顧客なしでは存在しないであろう、すなわちクレジットカードは常に顧客を有するであろうと仮定することができる。したがって、それらは次のような関係を持つべきです。
class Customer {
var card: CreditCard?
}
class CreditCard {
unowned let customer: Customer
}
Q3。 「所有されていない参照」は、C/C++の「ダングリングポインタ」のようなセキュリティリスクを参照します。
私はそうは思わない。
所有されていない参照は値を持つことが保証されている単なる弱い参照ですので、それは決してセキュリティ上のリスクではありません。ただし、参照しているインスタンスの割り当てが解除された後に所有されていない参照にアクセスしようとすると、ランタイムエラーが発生し、アプリケーションがクラッシュします。
それが私には見られる唯一のリスクです。
selfがクロージャでゼロになる可能性がある場合は、[weak self]を使用してください。
selfがクロージャ内で決してnilにならない場合は、[unowned self]を使用してください。
[unowned self]を使用したときにクラッシュした場合、selfはそのクロージャのある時点ではおそらくnilであり、おそらくを使用する必要があります。[weak self]代わりに。
クロージャでstrong、weak、および所有されていないの使用例を確認してください。 :
link からの抜粋
最後のポイント
所有されていない参照は、1つのオブジェクトが他の1つのオブジェクトによってのみ所有されるべきであるときに、2つのオブジェクト間のSame-Lifetime関係の場合に使用される一種の弱い参照です。オブジェクトとそのプロパティの1つの間に不変のバインディングを作成する方法です。
中間のSwift WWDCビデオで示されている例では、人はクレジットカードを所有しており、クレジットカードは1人の所有者しか持つことができません。クレジットカードでは、1人の所有者だけでクレジットカードを移動させたくないため、その人をオプションの施設にすることはできません。クレジットの保有者プロパティを弱い参照にすることでこのサイクルを破ることができますが、それには(定数ではなく)オプションで可変にする必要があります。この場合の所有されていない参照は、CreditCardがPersonの所有持分を持っていないにもかかわらず、その寿命がそれに依存することを意味します。
class Person {
var card: CreditCard?
}
class CreditCard {
unowned let holder: Person
init (holder: Person) {
self.holder = holder
}
}
ARC
ARCは、Appleの自動メモリ管理バージョンであるコンパイル時機能です。これは、自動参照カウントの略です。つまり、onlyは、オブジェクトへの参照がzero strongある場合に、オブジェクトのメモリを解放します。
STRONG
本質的には通常の参照(ポインターとすべて)ですが、それはそれ自体が特別なものですprotects保持されているカウントを1増やすことで、ARCによって割り当て解除されることから参照されるオブジェクトを取得します- 何かがある限りがオブジェクトへの強い参照を持っている場合、割り当ては解除されません。
一般的に、オブジェクトの階層関係がlinearの場合、強い参照を使用しても安全です。強い参照の階層が親から子に流れる場合、常に強い参照を使用しても問題ありません。
クラスインスタンス間の強い参照サイクルの解決
weak
およびunowned
変数を使用する重要な場所は、潜在的な保持サイクルがある場合です。保持サイクルは、2つのオブジェクトの両方が相互に強い参照を持っている場合に発生します。 2つのオブジェクトが相互に強力な参照を持っている場合、ARCはお互いを維持しているため、各インスタンスで適切なリリースメッセージコードを生成しません。
WEAK
弱い参照とは、オブジェクトがARCによって割り当て解除されないように保護しないとなるオブジェクトへのポインタです。強参照はオブジェクトの保持カウントを1増加させますが、弱参照しないです。さらに、弱い参照は、オブジェクトが正常に割り当て解除されると、オブジェクトへのポインタをゼロにします。これにより、弱参照にアクセスするときに、有効なオブジェクトまたはnil
のいずれかになります。
ARCは、参照するインスタンスの割り当てが解除されると、弱い参照を自動的にnilに設定します。また、弱参照は実行時に値を
nil
に変更できるようにする必要があるため、常にvariablesとして宣言されます。
使用
両方がnil
であることが許可されている2つのプロパティがある状況。このシナリオは、weak
参照で解決するのが最適です。
他のインスタンスのライフタイムがshorterの場合、つまり、最初に他のインスタンスの割り当てを解除できる場合は、weak
参照を使用します。
未所有
弱い参照のような非所有参照は、参照されているオブジェクトの保持カウントを増加させません。所有されていない参照は非ゼロです。これは、オブジェクトの割り当てが解除されても、ポインターがゼロにならないことを意味します。これは、所有されていない参照を使用すると、 ダングリングポインター になる場合があることを意味します。
ARCは非所有参照の値を決してnilに設定しません。つまり、非所有参照はnon-optionalタイプを使用して定義されます。
重要。
参照が常に割り当て解除されていないインスタンスを参照していることが確実な場合にのみ、所有されていない参照を使用します。
インスタンスの割り当てが解除された後、所有されていない参照の値にアクセスしようとすると、
Attempted to read an unowned reference but object was already deallocated
というランタイムエラーが発生します。
注意
Swiftは、実行時の安全性チェックを無効にする必要がある場合(パフォーマンス上の理由など)に、安全でない非所有参照も提供します。すべての安全でない操作と同様に、そのコードの安全性を確認する責任はユーザーにあります。
unowned(unsafe)
と記述することにより、安全でない非所有参照を示します。参照するインスタンスの割り当てが解除された後、安全でない非所有参照にアクセスしようとすると、プログラムは、インスタンスが以前使用されていたメモリ位置にアクセスしようとしますが、これは安全でない操作です。
使用
1つのプロパティがnil
であることが許可され、別のプロパティcannotがnil
である場合。このシナリオは、unowned
参照で解決するのが最適です。
他のインスタンスにsameライフタイムまたはlongerライフタイムがある場合、unowned
参照を使用します。 暗黙的にアンラップされたオプションのように、guarantee参照がnot使用時にnil
になることができる場合は、unowned
を使用します。そうでない場合は、weak
を使用する必要があります。