web-dev-qa-db-ja.com

弱い参照と所有されていない参照の違いは何ですか?

スウィフトは持っています:

  • 強い参照
  • 弱い参照
  • 未所有の参照

所有されていない参照は弱い参照とどう違うのですか?

所有されていない参照を使用しても安全なのはいつですか。

所有されていない参照は、C/C++では ぶら下がりポインタ のようなセキュリティ上のリスクがありますか?

220
Ian Ringrose

weakunownedの両方の参照は、参照先のオブジェクトに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 }
}

この例では、CustomerCreditCardを持っていてもいなくてもかまいませんが、CreditCardは常にCustomerに関連付けられます。これを表すために、Customerクラスにはオプションのcardプロパティがありますが、CreditCardクラスにはオプションではない(そして所有されていない)customerプロパティがあります。

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

CustomerおよびCreditCardの例は、1つのnilにすることが許可されているプロパティと、nilにすることができない別のプロパティが、強い参照サイクルを引き起こす可能性がある状況を示しています。このシナリオは、所有されていない参照で最もよく解決されます。

アップルからのメモ:

弱い参照は、それらの値が実行時に変わる可能性があることを示すために、変数として宣言する必要があります。弱い参照は定数として宣言できません。

両方のプロパティが常に値を持つべきで、初期化が完了するとどちらのプロパティもnilになるべきではないという3番目のシナリオもあります。

また、クロージャを扱うときに避けるべき古典的な保持サイクルのシナリオもあります。

このために、私はあなたが アップルのドキュメント を訪れるか、あるいはこの本を読む ことをお勧めします

327
Ilea Cristian

Q1。 「所有されていない参照」と「弱い参照」はどう違うのですか?

弱い参照:

弱い参照は、それが参照するインスタンスを強く保持しない参照であり、ARCが参照先のインスタンスを破棄しないようにするためのものではありません。弱参照は「値なし」を持つことが許可されているため、すべての弱参照はオプションの型を持つものとして宣言する必要があります。 (アップルドキュメント)

未所有の参考資料:

弱い参照のように、所有されていない参照は、それが参照するインスタンスを強く保持しません。弱い参照とは異なり、所有されていない参照は常に値を持つと見なされます。このため、所有されていない参照は常に非オプション型として定義されます。 (アップルドキュメント)

それぞれを使用する場合

その参照がその存続期間中のある時点でゼロになるのが有効であるときはいつでも弱い参照を使用してください。逆に、初期化中に設定された参照がnilにならないことがわかっている場合は、所有されていない参照を使用してください。 (アップルドキュメント)


Q2。 「未所有の参照」を使用しても安全なのはいつですか?

上記のように、所有されていない参照は常に値を持つと見なされます。そのため、参照がゼロにならないことが確実な場合にのみ使用してください。次の例を通じて、Apple Docsは所有されていない参照のユースケースを説明しています。

2つのクラスCustomerCreditCardがあるとします。顧客はクレジットカードなしで存在することができるが、クレジットカードは顧客なしでは存在しないであろう、すなわちクレジットカードは常に顧客を有するであろうと仮定することができる。したがって、それらは次のような関係を持つべきです。

class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let customer: Customer
}

Q3。 「所有されていない参照」は、C/C++の「ダングリングポインタ」のようなセキュリティリスクを参照します

私はそうは思わない。

所有されていない参照は値を持つことが保証されている単なる弱い参照ですので、それは決してセキュリティ上のリスクではありません。ただし、参照しているインスタンスの割り当てが解除された後に所有されていない参照にアクセスしようとすると、ランタイムエラーが発生し、アプリケーションがクラッシュします。

それが私には見られる唯一のリスクです。

アップルドキュメントへのリンク

25
Myxtic

selfがクロージャでゼロになる可能性がある場合は、[weak self]を使用してください。

selfがクロージャ内で決してnilにならない場合は、[unowned self]を使用してください。

[unowned self]を使用したときにクラッシュした場合、selfはそのクロージャのある時点ではおそらくnilであり、おそらくを使用する必要があります。[weak self]代わりに

クロージャでstrongweak、および所有されていないの使用例を確認してください。 :

https://developer.Apple.com/library/ios/documentation/Swift/conceptual/Swift_programming_language/AutomaticReferenceCounting.html

24
TenaciousJay

link からの抜粋

最後のポイント

  • 強い、弱い、または所有していないことを心配する必要さえあるかどうかを判断するには、「参照型を扱っているのですか」と尋ねます。構造体や列挙型を使用している場合、ARCはこれらの型のメモリを管理していないため、これらの定数または変数に弱いまたは不明なものを指定する必要はありません。
  • 強い参照は、親が子を参照する階層関係では問題ありませんが、その逆はありません。実際、強い参照はほとんどの場合最も適切な種類の参照です。
  • 2つのインスタンスが相互に関連している場合は、それらのインスタンスの一方が他方に対して弱い参照を保持していることを確認してください。
  • 一方のインスタンスが他方のインスタンスなしでは存在できないように2つのインスタンスが関連付けられている場合、必須の依存関係を持つインスタンスは、他のインスタンスへの所有されていない参照を保持する必要があります。
4
Abhinav Singh

所有されていない参照は、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
    }
}
0
JuJoDi

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であることが許可され、別のプロパティcannotnilである場合。このシナリオは、unowned参照で解決するのが最適です。

他のインスタンスにsameライフタイムまたはlongerライフタイムがある場合、unowned参照を使用します。 暗黙的にアンラップされたオプションのように、guarantee参照がnot使用時にnilになることができる場合は、unownedを使用します。そうでない場合は、weakを使用する必要があります。

doc および source を読むことを強くお勧めします

0
yoAlex5