スウィフトには次のものがあります。
- 強力な参照
- 弱参照
- 所有されていない参照
非所有参照と弱参照の違いは?
所有されていない参照を安全に使用できるのはいつですか?
所有されていない参照は、C/C++のダングリング ポインターのようなセキュリティ リスクですか?
スウィフトには次のものがあります。
非所有参照と弱参照の違いは?
所有されていない参照を安全に使用できるのはいつですか?
所有されていない参照は、C/C++のダングリング ポインターのようなセキュリティ リスクですか?
との両方weak
のunowned
参照は、参照されたオブジェクトに保持を作成しませんstrong
(別名、ARC が参照されたオブジェクトの割り当てを解除するのを防ぐために、保持カウントを増やしません)。
しかし、なぜ 2 つのキーワードを使用するのでしょうか。この違いは、Optional
型が Swift 言語に組み込まれているという事実に関係しています。それらについての簡単な話:オプションの型はメモリの安全性を提供します (これは、この利点を提供するために厳密なSwift のコンストラクター規則で美しく機能します)。
weak
参照により、それが可能になる可能性がありますnil
(これは、参照されたオブジェクトの割り当てが解除されると自動的に発生します)。したがって、プロパティの型はオプションでなければなりません。コンパイラは、できる限り安全なコードを書くように強制します)。
参照は、その存続期間中unowned
は決してならないことを前提としていますnil
。所有されていない参照は、初期化中に設定する必要があります。これは、参照が、チェックなしで安全に使用できる非オプションの型として定義されることを意味します。参照されているオブジェクトの割り当てが解除された場合、所有されていない参照が使用されるとアプリがクラッシュします。
アップルのドキュメントから:
弱参照は、その参照が存続期間中のある時点で 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
例は、どちらも nil が許可されている 2 つのプロパティが強い参照サイクルを引き起こす可能性がある状況を示しています。このシナリオは、弱参照で解決するのが最適です。両方のエンティティは、他方に厳密に依存することなく存在できます。
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
例は、nil が許可されている 1 つのプロパティと、nil にできない別のプロパティが強い参照サイクルを引き起こす可能性がある状況を示しています。このシナリオは、所有されていない参照で解決するのが最適です。
Apple からのメモ:
弱参照は変数として宣言して、その値が実行時に変更される可能性があることを示す必要があります。弱参照は定数として宣言できません。
両方のプロパティが常に値を持つ必要があり、初期化が完了したらどちらのプロパティも決して nil にしないという 3 番目のシナリオもあります。
また、クロージャーを操作するときに避けるべき、従来のリテイン サイクル シナリオもあります。
これについては、 Apple のドキュメントにアクセスするか、本を読むことをお勧めします。
Q1. 「非所有参照」と「弱い参照」の違いは何ですか?
弱参照:
弱参照とは、参照先のインスタンスを強力に保持しない参照であるため、ARC が参照先のインスタンスを破棄するのを止めません。弱参照には「値なし」が許可されているため、すべての弱参照をオプションの型として宣言する必要があります。(アップルのドキュメント)
未所有の参照:
弱い参照と同様に、所有されていない参照は、それが参照するインスタンスを強力に保持しません。ただし、弱い参照とは異なり、所有されていない参照は常に値を持つと見なされます。このため、所有されていない参照は常に非オプションの型として定義されます。(アップルのドキュメント)
それぞれをいつ使用するか:
弱参照は、その参照が存続期間中のある時点で nil になることが有効な場合はいつでも使用してください。逆に、初期化中に設定された参照が nil にならないことがわかっている場合は、所有されていない参照を使用します。(アップルのドキュメント)
Q2. 「所有されていない参照」を安全に使用できるのはいつですか?
上で引用したように、所有されていない参照は常に値を持つと想定されます。したがって、参照が決して nil にならないことが確実な場合にのみ使用してください。Apple Docs は、次の例を通じて、所有されていない参照の使用例を示しています。
と の 2 つのクラスがあるCustomer
としCreditCard
ます。顧客はクレジット カードがなくても存在できますが、顧客がいなければクレジット カードは存在しません。つまり、クレジット カードには常に顧客がいると想定できます。したがって、それらは次の関係を持つ必要があります。
class Customer {
var card: CreditCard?
}
class CreditCard {
unowned let customer: Customer
}
Q3. 「所有されていない参照」は、C/C++ の「ダングリング ポインター」のようなセキュリティ リスクを参照しますか?
私はそうは思わない。
所有されていない参照は、値を持つことが保証されている単なる弱い参照であるため、セキュリティ リスクになることはありません。ただし、参照するインスタンスの割り当てが解除された後に、所有されていない参照にアクセスしようとすると、ランタイム エラーが発生し、アプリがクラッシュします。
それが私が見た唯一のリスクです。
クロージャでselfが nil になる可能性がある場合は、 [weak self]を使用します。
クロージャでselfが決して nil にならない場合は、 [unowned self]を使用します。
[unowned self]を使用したときにクラッシュする場合は、おそらくそのクロージャのある時点で self が nil であり、代わりに[weak self]を使用する必要があります。
クロージャーでのstrong、weak、およびunownedの使用例を確認してください。
リンクから抜粋
いくつかの結論
所有されていない参照は、オブジェクトが他の 1 つのオブジェクトによってのみ所有されるべきである場合に、2 つのオブジェクト間の Same-Lifetime 関係の場合に使用される一種の弱い参照です。これは、オブジェクトとそのプロパティの 1 つとの間に不変のバインディングを作成する方法です。
中間の迅速な WWDC ビデオで示されている例では、個人がクレジット カードを所有しており、クレジット カードには 1 つの所有者しか存在できません。クレジット カードでは、所有者が 1 人しかいないクレジット カードを持ちたくないため、個人を任意のプロパティにすることはできません。クレジットの所有者プロパティを弱参照にすることで、このサイクルを断ち切ることができますが、それには、(定数ではなく) 変数だけでなく、オプションにする必要もあります。この場合の所有されていない参照は、CreditCard が Person を所有していないが、その寿命はそれに依存していることを意味します。
class Person {
var card: CreditCard?
}
class CreditCard {
unowned let holder: Person
init (holder: Person) {
self.holder = holder
}
}