未拥有 vs 弱引用。为什么我们应该更喜欢未拥有?

17

正如苹果公司在《The Swift Programming Language》中所说,每当可能时,我们应该更喜欢使用unowned而不是weak

如果捕获的引用永远不会变为nil,它就应该始终作为一个unowned引用被捕获,而不是一个weak引用。

来自此页面的“Weak and Unowned References”部分。

我知道这两者之间的区别,但我好奇是否有任何充分的理由更喜欢unowned而不是weak? 我认为weak更安全,我们只需要编写[weak obj]和可选绑定检查,而不必考虑obj存在的可能性。

这与一些性能方面的考虑或是我所遗漏的某些内容有关吗?或者,始终使用weak代替unowned完全可以吗?

2个回答

26

弱引用指向的对象被释放后会自动设置为nil。为了在Swift中实现这一点,这些弱引用必须声明为var并且是可选的:

class SomeOtherClass {
    weak var weakProperty: SomeClass?
}

如果weakPropertySomeOtherClass实例仍然存在并且在使用之前我们想要检查它(代理就是这样的一个例子),那么这样做没问题。但是,如果某个引用永远不应该逻辑上为nil,而我们仍然希望防止保留循环,则怎么办?在Objective-C中,任何对象引用都可以是nil(向nil发送消息始终会静默失败),因此没有困境,我们总是使用weak。但是Swift根本没有可空引用。我们使用可选项来表示语义上缺少值的内容。但是我们不应被迫使用可选项来表示始终具有值的内容,只是为了能够打破保留循环。这种做法将违反可选项预期的语义。

这就是unowned发挥作用的地方。它有两种类型:unowned(safe)unowned(unsafe)。后者是危险的,相当于Objective-C中的assignunsafe_unretained。但是前者是默认值(至少在调试时是这样;不确定它是否在发布版本中优化为unowned(unsafe)),如果引用的对象过早释放,它将可靠地使您的应用程序崩溃。当出现问题时,您的应用程序会崩溃,但这比静默失败要容易得多。只有在您确实希望如此时(在这种情况下,您将使用weak),它才应该静默失败。


有道理。谢谢你的回答。 - onevcat

1

Swift 强引用、弱引用、无主引用

[Objective-C 属性特性]

ARC - 自动引用计数 是一种管理内存的机制,适用于引用类型[关于]。只有当对象的引用计数为0时,该对象才会被释放。

强引用 - 默认设置,并且在线性关系(没有循环)中使用这种类型是安全的。

保留环 - 当每个对象都对彼此有强引用时,就会出现这种情况。

打破一个保留环:使用弱引用无主引用。它们都不会使对象的引用计数增加+1,并且有以下区别。

弱引用 - 当一个被引用的对象被释放(变为nil),ARC 也会将 weak 引用设置为 nil。这就是为什么 weak 引用是一个变量 var(不能是常量 let[var vs let],也是一个可选项 optional

weak var delegate: <Type>?

常规

unowned - 当引用的对象被释放(即为nil)时,unowned 不会 变成nil,因为ARC不会设置它。这就是为什么unowned引用是非可选的

默认情况下为unowned

safe unowned - 使用运行时安全检查来抛出异常,如果unowned引用已被释放。

Fatal error: Attempted to read an unowned reference but object 0x7fa5dad3f0f0 was already deallocated

unowned(unsafe)

unowned(unsafe) 通过 UnsafePointer 操作,可以创建一个 dangling pointer。它类似于 Objective-C 中的 __unsafe_unretained。这是一种直接内存访问方式,ARC 无法处理。它可能会产生意外的行为,而不仅仅是崩溃。它具有更好的性能。

EXC_BAD_ACCESS

[EXC_BAD_ACCESS]
[Closure示例]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接