无主 var something 之间的区别:Something!和弱 var something:something!在 Swift 中

Difference between unowned var something: Something! and weak var something: Something! in Swift

提问人:Roman Podymov 提问时间:8/11/2023 最后编辑:Roman Podymov 更新时间:8/11/2023 访问量:67

问:

请看下面给出的以下示例:

protocol Something: AnyObject { 
    func f()
}

class A {
    unowned var something1: Something!
    weak var something2: Something!

    func f() {
        something1.f()
        something2.f()
    }
}

type of 和 和有什么不一样?something1something2

swift 弱引用 unowned-references

评论


答:

1赞 HangarRash 8/11/2023 #1

快速摘要:

weak var something2: Something!很糟糕,因为您实际上是在强制解包一个变量,该变量假定 (via ) 在设置后的某个未来时间。weaknil

unowned var something1: Something!更好。仅当假定变量引用的有效期将超过变量的生存期时,才使用 of。让它隐式解包假设它永远不会在给定值后变为。unownednil

详。让我们将其分解为几个部分。

  1. 和 和有什么不一样?weakunowned

    摘自 Swift 书中的 ARC 章节 - 弱参考文献

    弱引用是指不对其引用的实例保持强保留的引用,因此不会阻止 ARC 释放引用的实例。此行为可防止引用成为强引用循环的一部分。通过将 weak 关键字放在属性或变量声明之前来指示弱引用。

    由于弱引用不会对它所引用的实例保持强保留,因此当弱引用仍在引用它时,该实例可能会被释放。因此,当它引用的实例被释放时,ARC 会自动将弱引用设置为 nil。而且,由于弱引用需要允许在运行时将其值更改为 nil,因此它们始终声明为可选类型的变量,而不是常量。

    摘自 Swift 一书中的 ARC 章节 - 无主参考文献

    与弱引用一样,无主引用不会对它所引用的实例保持强保留。但是,与弱引用不同的是,当另一个实例具有相同生存期或更长的生存期时,将使用无主引用。通过将 unowned 关键字放在属性或变量声明之前来指示无主引用。

    与弱引用不同,无主引用应始终具有值。因此,将值标记为无主值不会使其成为可选值,并且 ARC 从不将无主引用的值设置为 nil。

    摘自 Swift 一书中的 ARC 章节 - 无主可选

    可以将对类的可选引用标记为无主。就 ARC 所有权模型而言,无主可选引用和弱引用都可以在相同的上下文中使用。区别在于,当您使用无主的可选引用时,您有责任确保它始终引用有效对象或设置为 nil。

  2. 什么是隐式解包可选 (IUO)?

    摘自 Swift 书籍中的“基础”一章 - 隐式展开的可选选项

    如上所述,可选选项表示允许常量或变量具有“无值”。可以使用 if 语句检查可选值以查看值是否存在,并且可以使用可选绑定有条件地解包以访问可选值(如果确实存在)。

    有时,从程序的结构中可以清楚地看出,在首次设置该值之后,可选值将始终具有一个值。在这些情况下,无需在每次访问可选值时检查和解包该值,因为可以安全地假定它始终具有值。

这对弱 var something2: Something! 意味着什么?

根据 和 的描述,有一个既是 又是矛盾的变量。 假定它将在设置后的某个时间点设置为。 假设一旦给定一个值,它就不会为零。weakIUOweakIUOweaknilIUO

因此,如果您有并且稍后尝试,如果已设置为直接或由于引用被释放而将其设置为 ARC 将其设置为,您的程序将崩溃。weak var something2: Something!something2.f()something2nilnil

使用 the 是你告诉编译器“相信我,它永远不会为零”的方式。但是 的用法是告诉编译器“小心,它可能是零”。那是一段注定要离婚的婚姻。IUOweak

这对无主的 var something1: Something!意味着什么?

与 不同,变量可以是可选的,也可以是非可选的。An 是可选的,但它排除了像处理可选一样处理它的需要。所以 an 是可选的。weakunownedIUOunowned IUO

根据 和 的描述,有一个既是 和 的变量,有点多余,但很有用。创建变量意味着确保它在设置后保持非 nil 值。 假设一旦给定一个值,它就不会为零。所以两者都有相同的目标。unownedIUOunownedIUOunownedIUO

由于 ,它没有很强的参考性,因此它具有 .但是,作为可选对象意味着您有责任确保它保持对有效对象的引用或显式设置为(因为 ARC 不会为您这样做)。由于,您假设它永远不会存在,因此您不必添加通常与可选项一起使用的所需语法。unownedweakunownednilIUOnil

因此,如果您有并且稍后尝试,如果引用已释放的对象或已显式设置为 ,则程序将崩溃。unowned var something1: Something!something1.f()something1nil

总结:

不要使用 .这是一场等待发生的崩溃。weak var something: Something!

如果可以在初始值设定项或声明的作用域中设置值,则使用,不需要强引用,并且引用在设置后将保持有效。unowned var something: Something

如果无法在初始值设定项或声明的作用域中设置值,则使用,在设置之前不会尝试访问变量,不需要强引用,并且设置初始值后引用将保持有效。unowned var something: Something!

如果不需要强引用,请使用,则引用在设置时将保持有效,并且您可能希望在某个时候显式设置该值。unowned var something: Something?nil

请记住,如果引用的实例已解除分配,则所有 的使用都可能导致崩溃。因此,只有在您知道不会发生这种情况时才使用。unownedunowned