What is the difference between a weak reference and an unowned reference?

Swift has:

  • Strong References
  • Weak References
  • Unowned References
  • How is an unowned reference different from a weak reference?

    When is it safe to use an unowned reference?

    Are unowned references a security risk like dangling pointers in C/C++?


    Both weak and unowned references do not create a strong hold on the referred object (aka they don't increase the retain count in order to prevent ARC from deallocating the referred object).

    But why two keywords? This distinction has to do with the fact that Optional types are built-in the Swift language. Long story short about them: optional types offer memory safety (this works beautifully with Swift's constructor rules - which are strict in order to provide this benefit).

    A weak reference allows the posibility of it to become nil (this happens automatically when the referenced object is deallocated), therefore the type of your property must be optional - so you, as a programmer, are obligated to check it before you use it (basically the compiler forces you, as much as it can, to write safe code).

    An unowned reference presumes that it will never become nil during it's lifetime. A unowned reference must be set during initialization - this means that the reference will be defined as a non-optional type that can be used safely without checks. If somehow the object being referred is deallocated, then the app will crash when the unowned reference will be used.

    From the Apple docs:

    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.

    In the docs there are some examples that discusses retain cycles and how to break them. All these examples are extracted from the docs.

    Example for the weak keyword:

    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?
    }
    

    And now, for some ASCII art (you should go see the docs - they have pretty diagrams):

    Person ===(strong)==> Apartment
    Person <==(weak)===== Apartment
    

    The Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference. Both entities can exist without having a strict dependency upon the other.

    Example for the unowned keyword:

    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 }
    }
    

    In this example, a Customer may or may not have a CreditCard , but a CreditCard will always be associated with a Customer . To represent this, the Customer class has an optional card property, but the CreditCard class has a non-optional (and unowned) customer property.

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

    The Customer and CreditCard example shows a situation where one property that is allowed to be nil and another property that cannot be nil have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.

    Note from Apple:

    Weak references must be declared as variables, to indicate that their value can change at runtime. A weak reference cannot be declared as a constant.

    There is also a third scenario when both properties should always have a value, and neither property should ever be nil once initialization is complete.

    And there are also the classic retain cycle scenarios to avoid when working with closures.

    For this, I encourage you to visit the Apple docs, or read the book.


    Q1. How is an “Unowned reference” different from a “Weak Reference”?

    Weak Reference:

    A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. Because weak references are allowed to have “no value”, you must declare every weak reference as having an optional type. (Apple Docs)

    Unowned Reference:

    Like weak references, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is assumed to always have a value. Because of this, an unowned reference is always defined as a non-optional type. (Apple Docs)

    When to Use Each:

    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. (Apple Docs)


    Q2. When is it safe to use an “unowned reference”?

    As quoted above, an unowned reference is assumed to always have a value. So you should only use it when you are sure that the reference will never be nil. Apple Docs illustrate a use-case for unowned references through the following example.

    Suppose we have two classes Customer and CreditCard . A customer can exist without a credit card, but a credit card will not exist without a customer, ie it can be assumed that a credit card will always have a customer. So, they should have the following relationship:

    class Customer {
        var card: CreditCard?
    }
    
    class CreditCard {
        unowned let customer: Customer
    }
    

    Q3. Are “unowned reference” reference an security risk like “dangling pointers” in C/C++

    I don't think so.

    Since unowned references are just weak references that are guaranteed to have a value, it shouldn't be a security risk in any way. However, if you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error, and the app will crash.

    That's the only risk I see with it.

    Link to Apple Docs


    If self could be nil in the closure use [weak self] .

    If self will never be nil in the closure use [unowned self] .

    If it's crashing when you use [unowned self] then self is probably nil at some point in that closure and you probably need to use [weak self] instead.

    Check out the examples on using strong , weak , and unowned in closures:

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

    链接地址: http://www.djcxy.com/p/37676.html

    上一篇: 你如何计算字符串中的字符串(实际上是一个字符)的出现?

    下一篇: 弱引用和无主引用之间有什么区别?