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


240

スウィフトは:

  • 強い参照
  • 弱い参照
  • 所有されていない参照

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

所有されていない参照を使用しても安全ですか?

所有されていない参照は、C / C ++のダングリングポインターのようなセキュリティリスクですか?



私の経験は、私unownedたちが制御するクラス、Appleクラスの場合に使用するweakことです。それが何をするかを確実に保証することはできないためです
onmyway133

@NoorAli、または「ownedBy」は「所有されていない」参照が所有者を指すことが多いため。
Ian Ringrose 2016

回答:


361

weakunowned参照はどちらも、参照さ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例を示すゼロであることが許可されている両方が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にならないという3番目のシナリオもあります。

また、クロージャを操作する際に回避する古典的な保持サイクルのシナリオもあります。

これについては、Appleのドキュメントにアクセスするか、本を読むことをお勧めします。


3
これはいくぶん取るに足らないことですが、ApartmentとPersonの例はやや混乱しており、強い参照サイクルを打破するための追加の解決策を示しています。人のアパートはオプションであり、したがってnilにすることができます。また、アパートのテナントはオプションであり、nilにすることができるため、両方のプロパティを弱いと定義できます。`` `
ジャスティンレヴィ冬

クラスPerson {let name:String init(name:String){self.name = name} weak var apartment:Apartment?} class Apartment {let number:Int init(number:Int){self.number = number} weak var tenant:Person?}
ジャスティンレヴィ冬

3
違い何weak var Person?対はvar Person?
2014年

4
@JustinLevi、両方のプロパティを弱いものとして宣言すると、それらの割り当てが解除される可能性があります。その人はアパートへの強い参照を保持するので、アパートは割り当て解除されません。アパートがPersonに対して同じ強い参照を持つ場合、それらは保持サイクルを作成します-プログラマーがそれを知っている場合、プログラマーが実行時にそれを壊す可能性がありますが、それ以外の場合は単なるメモリリークです。ARCが私たちのためにすべての汚いことをするので、これは強い、弱い、そして所有されていないことについてのすべての大騒ぎです:より高いレベルでのメモリ管理。保持サイクルを回避することが私たちの仕事です。
Ilea Cristian 2014

1
非所有者の弱点に対する唯一の利点は、アンラップする必要がなく、定数を使用できることですか?ウィークを使用できず、所有されていないものしか使用できないインスタンスはありますか?
アラン

29

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 ++の「ダングリングポインター」のようなセキュリティリスクを参照していますか

そうは思いません。

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

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

Appleドキュメントへのリンク


所有されていないことについて理解しやすいQ2サンプルプログラム..ありがとうございます。弱いタイプと強いタイプの同じタイプの例を追加できますか?
Ranjith Kumar

優れた。ありがとうございました。
Swifty McSwifterton 2015年

所有されていないか弱いの一般的な例を含めることができますか?
ハニー(

親と子のオブジェクトを検討してください。子が親なしでは存在できない場合unownedは、子クラスの親のプロパティに使用します。弱いとは逆です。素晴らしい説明@myxtic! unowned参照はweak、値を持つことが保証されている単なる参照です!
2017

26

クロージャでセルフがnilの場合は、[weak self]を使用します。

クロージャーで自分自身がnilにならない場合は、[unowned self]を使用します。

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

クロージャーでstrongweak、およびunownedを使用する例を確認してください。

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html


7
たとえ自分がnilになることができないとしても、weakを使用しないでください。害はありません。
2016年

4
こんにちは@Boon-それは確かに重要な質問です。
Fattie

[弱い自己] => viewDidLoad()内でクロージャを使用する場合、どのselfようにしてnil にすることができますか?
Hassan Tareq 2017

@HassanTareq、私は上記の記事でいくつかの良い例が言及されていると思います。特に、「クロージャの強力な参照サイクルの解決」セクションをチェックしてください。引用: "Swiftでは、クロージャー内でselfのメンバーを参照するときは常に、(somePropertyまたはsomeMethod()ではなく)self.somePropertyまたはself.someMethod()を記述する必要があります。これにより、事故。" 抜粋:Apple Inc.「The Swift Programming Language(Swift 4)」iBooksの。itunes.apple.com/de/book/the-swift-programming-language-swift-4/...
ニックEntin

1
@Boon常にweakを使用する場合、コンパイラーは使用前にオプションをチェックすることを強制します。このチェックを行わなかった場合、コンパイル時にエラーが発生します。他の害はありません。
Vikas Mishra

5

リンクからの抜粋

いくつかの結論点

  • 強い、弱い、または所有されていないことについて心配する必要があるかどうかを判断するには、「参照型を扱っていますか」と質問します。StructsまたはEnumsを使用している場合、ARCはそれらのタイプのメモリを管理していないため、これらの定数または変数にウィークまたは非所有を指定することについて心配する必要さえありません。
  • 強い参照は、親が子を参照する階層関係では問題ありませんが、その逆は当てはまりません。実際、強い参照は、ほとんどの場合、最も適切な種類の参照です。
  • 2つのインスタンスがオプションで相互に関連付けられている場合、それらのインスタンスの1つがもう1つのインスタンスへの弱い参照を保持していることを確認してください。
  • 2つのインスタンスが関連し、一方のインスタンスが他方なしでは存在できない場合、必須の依存関係を持つインスタンスは、他方のインスタンスへの所有されていない参照を保持する必要があります。

1

weakunowned参照の両方がオブジェクトの参照カウントに影響を与えることはありません。ただし、弱参照は常にオプションになります。つまり、nilにすることができますが、unowned参照をnilにすることはできません。オプションの参照を使用する場合、オブジェクトがnilになる可能性を常に処理する必要があります。所有されていない参照の場合は、オブジェクトがnilにならないようにする必要があります。nilオブジェクトへの所有されていない参照を使用することは、nilであるオプションを強制的にアンラップすることに似ています。

つまり、オブジェクトのライフタイムが参照よりも長いことが確実な場合は、所有されていない参照を使用しても安全です。そうでない場合は、代わりに弱い参照を使用することをお勧めします。

質問の3番目の部分については、所有されていない参照がぶら下がりポインタに似ているとは思いません。参照カウントについて話すとき、通常はオブジェクトの強い参照カウントを指します。同様に、swiftはオブジェクトの所有されていない参照カウントと弱い参照カウントを維持します(弱い参照は、オブジェクト自体ではなく、「サイドテーブル」と呼ばれるものを指します)。強い参照カウントがゼロに達すると、オブジェクトは初期化解除されますが、所有されていない参照カウントがゼロより大きい場合は、割り当てを解除できません。

ここで、ダングリングポインターは、既に割り当て解除されているメモリの場所を指すものです。ただし、オブジェクトへの所有されていない参照がある場合に限り、メモリの割り当てを解除できるので、すぐに宙ぶらりんのポインタが発生することはありません。

迅速なメモリ管理について詳しく説明している記事はたくさんあります。こちらです。


0

所有されていない参照は、2つのオブジェクト間のSame-Lifetime関係の場合に使用される一種の弱い参照であり、オブジェクトは常に他の1つのオブジェクトによってのみ所有されるべきです。これは、オブジェクトとそのプロパティの1つとの間に不変のバインディングを作成する方法です。

中間の迅速なWWDCビデオで示されている例では、人はクレジットカードを所有しており、クレジットカードは1人の所有者しか持てません。クレジットカードでは、所有者が1人だけのクレジットカードを持ち歩きたくないので、その人はオプションのプロパティにしないでください。クレジットのホルダープロパティを弱い参照にすることで、このサイクルを壊すことができますが、それを(定数ではなく)変数だけでなくオプションにすることも必要です。この場合の所有されていない参照とは、CreditCardがPersonに所有権を持たないが、その寿命はそれに依存することを意味します。

class Person {
    var card: CreditCard?
}

class CreditCard {

    unowned let holder: Person

    init (holder: Person) {
        self.holder = holder
    }
}

wwdcビデオまたはタイトルへのリンク?
Osa

-2

unownedあなたがその時点でアクセスするポイントに決していることselfができないと確信しているときに使用してください。nilself

例(もちろん、ターゲットをから直接追加できますがMyViewController、これも簡単な例です):

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let myButton = MyButton { [unowned self] in
            print("At this point, self can NEVER be nil. You are safe to use unowned.")
            print("This is because myButton can not be referenced without/outside this instance (myViewController)")
        }
    }
}

class MyButton: UIButton {
    var clicked: (() -> ())

    init(clicked: (() -> ())) {
        self.clicked = clicked

        // We use constraints to layout the view. We don't explicitly set the frame.
        super.init(frame: .zero)

        addTarget(self, action: #selector(clicked), for: .touchUpInside)
    }

    @objc private func sendClosure() {
        clicked()
    }
}

アクセスするweak可能性selfがある場合にご利用ください。nilself

例:

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NetworkManager.sharedInstance.receivedData = { [weak self] (data) in
            print("Can you guarentee that self is always available when the network manager received data?")
            print("Nope, you can't. Network manager will be alive, regardless of this particular instance of MyViewController")
            print("You should use weak self here, since you are not sure if this instance is still alive for every")
            print("future callback of network manager")
        }
    }
}

class NetworkManager {

    static let sharedInstance = NetworkManager()

    var receivedData: ((Data) -> ())?

    private func process(_ data: Data) {
        // process the data...

        // ... eventually notify a possible listener.
        receivedData?(data)
    }
}

の短所unowned

  • 弱いよりも効率的
  • あなたは(まあ、あなたは強制されます)インスタンスを不変としてマークすることができます(Swift 5.0以降ではもうありません)。
  • コードの読者に示します:このインスタンスはXと関係があり、それなしでは生きられませんが、Xが存在しない場合、私も存在します。

の短所weak

  • 所有していないよりも安全です(クラッシュしないため)。
  • 双方向のXとの関係を作成できますが、どちらもお互いなしで生きることができます。

不明な場合は、を使用してくださいweak待って、私はここであなたのケースで何をすべきかをStackOverflowでここに尋ねることを意味する!使用すべきでないときにいつもweakを使用することは、あなたとあなたのコードの読者を混乱させるだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.