首页 文章

弱引用和无引用引用之间有什么区别?

提问于
浏览
210

斯威夫特有:

  • 强引用

  • 弱引用

  • 无主参考文献

如何将无主参考与弱参考不同?

什么时候使用无主参考安全?

无主引用是否存在C / C中的dangling pointers等安全风险?

6 回答

  • 0

    weakunowned 引用都不会在引用的对象上创建 strong hold(a.k.a . 它们不会增加保留计数以防止ARC释放引用的对象) .

    但为什么两个关键词?这种区别与 Optional 类型内置Swift语言的事实有关 . 长话短说他们:optional types提供记忆安全(这与Swift's constructor rules很好地合作 - 这是严格的,以提供这种好处) .

    weak 引用允许它的可能性变为 nil (当引用的对象被释放时会自动发生),因此您的属性类型必须是可选的 - 因此作为程序员,您有义务在使用它之前检查它(基本上,编译器会尽可能地强制您编写安全代码 .

    unowned 引用假定它在其生命周期中永远不会成为 nil . 必须在初始化期间设置无主引用 - 这意味着引用将被定义为非可选类型,可以安全地使用而无需检查 . 如果被引用的对象以某种方式被释放,那么当使用无主参考时,应用程序将崩溃 .

    来自Apple docs

    只要对于该引用有效的弱引用在其生命周期的某个时刻变为零,就使用弱引用 . 相反,当您知道在初始化期间设置引用后永远不会为nil时,请使用无主引用 .

    在文档中有一些例子讨论了保留周期以及如何打破它们 . 所有这些示例都是从the 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艺术(你应该去see the docs - 他们有漂亮的图表):

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

    PersonApartment 示例显示了两个属性(均允许为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 will alwaysCustomer 相关联 . 为了表示这一点, Customer 类具有可选的 card 属性,但 CreditCard 类具有非可选(和无主) customer 属性 .

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

    CustomerCreditCard 示例显示了一种情况,即允许一个属性为nil,另一个不能为nil的属性可能导致强引用循环 . 使用无主引用可以最好地解决此方案 .

    Apple的注意事项:

    弱引用必须声明为变量,以指示它们的值可以在运行时更改 . 弱引用不能声明为常量 .

    还有第三种情况,两个属性应始终具有值,并且一旦初始化完成,这两个属性都不应为nil .

    还有一些经典的保留周期场景,以避免在使用闭包时 .

    为此,我建议您访问Apple docs,或阅读the book .

  • -1

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

    弱参考:

    弱引用是一种引用,它不会强制保留它所引用的实例,因此不会阻止ARC处理引用的实例 . 因为弱引用被允许具有“无值”,所以必须将每个弱引用声明为具有可选类型 . (Apple Docs)

    无主参考:

    就像弱引用一样,无主引用并不会强烈保留它引用的实例 . 然而,与弱引用不同,假定无主引用始终具有值 . 因此,无主引用始终定义为非可选类型 . (Apple Docs)

    何时使用每个:

    只要对于该引用有效的弱引用在其生命周期的某个时刻变为零,就使用弱引用 . 相反,当您知道在初始化期间设置引用后永远不会为nil时,请使用无主引用 . (Apple Docs)


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

    如上所述,假定无主参考始终具有值 . 因此,只有在确定引用永远不会为零时才应使用它 . Apple Docs通过以下示例说明了无主引用的用例 .

    假设我们有两个类 CustomerCreditCard . 客户可以在没有信用卡的情况下存在,但是没有客户就不会存在信用卡,即可以假设信用卡将始终拥有客户 . 所以,他们应该有以下关系:

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

    我不认为所以 .

    由于无主引用只是保证具有值的弱引用,因此它不应该以任何方式存在安全风险 . 但是,如果在释放引用的实例后尝试访问无主引用,则会触发运行时错误,应用程序将崩溃 .

    这是我看到的唯一风险 .

    Link to Apple Docs

  • 4

    来自Jon Hoffman的书“Mastering Swift 4.”:

    弱引用和无引用引用之间的区别在于弱引用所引用的实例可以是nil,而无主引用所引用的实例不能为nil . 这意味着当我们使用弱引用时,该属性必须是可选属性,因为它可以是nil .

  • 303

    如果 self 在闭包中可能为零,请使用 [weak self] .

    如果 self 在闭包中永远不会是nil,请使用 [unowned self] .

    如果它在你使用 [unowned self] 时崩溃,那么self在该闭包的某个时刻可能是零,你可能需要使用 [weak self] .

    查看闭包中使用 strongweakunowned 的示例:

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

  • 23

    摘录自link

    结论要点很少

    • 要确定您是否需要担心强,弱或无主,请问“我是否在处理参考类型” . 如果您正在使用Structs或Enums,ARC不管理这些类型的内存,您甚至不必担心为这些常量或变量指定弱或无内容 .

    • 在父级引用子级的层次关系中,强引用很好,但反之亦然 . 实际上,强引用是大多数时候最适合的参考 .

    • 当两个实例可选地彼此相关时,请确保其中一个实例保持对另一个实例的弱引用 .

    • 当两个实例相关联时,其中一个实例在没有另一个实例的情况下不能存在,具有强制相关性的实例需要保持对另一个实例的无主引用 .

  • 22

    无主引用是一种弱引用,用于两个对象之间的Same-Lifetime关系,当一个对象只能由另一个对象拥有时 . 这是一种在对象和其中一个属性之间创建不可变绑定的方法 .

    在中间swift WWDC视频中给出的示例中,一个人拥有信用卡,而信用卡只能拥有一个持有者 . 在信用卡上,此人不应该是可选的 property ,因为您不希望只有一个所有者的信用卡 . 您可以通过使信用证上的持有者属性成为弱引用来打破此循环,但这也要求您使其成为可选和变量(而不是常量) . 在这种情况下,无主参考意味着尽管CreditCard没有人的拥有权,但其生命依赖于它 .

    class Person {
        var card: CreditCard?
    }
    
    class CreditCard {
    
        unowned let holder: Person
    
        init (holder: Person) {
            self.holder = holder
        }
    }
    

相关问题