未拥有引用有什么好处?

7

弱引用和无主引用用于防止两个对象相互持有引用而导致的循环引用问题。我理解弱引用的使用,但不理解无主引用的使用。以下是苹果提供的一个场景示例,其中一个对象应该使用无主引用:

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

这个想法是,没有客户就无法存在信用卡。因此,信用卡可以省去使用弱引用所需的可选解包步骤,并可以使用无主引用。嗯...那为什么不使用强引用呢?如果所有其他对客户的引用都消失了(这不应该发生?),那么信用卡使用拥有的引用会导致崩溃;而使用强引用则会导致内存泄漏。哎呀?两害相权取其轻?最好崩溃,因为这更容易在开发和测试期间被注意到。请给予一些见解。谢谢。
6个回答

4
更好的做法是崩溃,因为这更容易在开发和测试过程中被注意到吗?
是的。
好吧,不完全是这样。
想法是你的应用程序设计应确保没有CreditCard实例超出其相应的Customer实例的生命周期。当您使用unowned时,您信任自己拥有一个逻辑上保证无崩溃执行的设计。
那么,为什么有人会使用unowned而不是weak?简单!unowned消除了整个Optional解包的麻烦,如果您知道您的CreditCard实例永远不会超出其相应的Customer实例,则应尽可能使用unowned。

嗨,Vatsal。那么,为什么不使用强引用?通过使引用未拥有,可以获得什么? - Verticon
1
@RobertVaessen 这将创建一个**保留循环(retain cycle)**,从而导致内存泄漏。客户实例将等待卡实例放弃对客户实例的所有权,而卡实例将等待客户实例放弃对卡实例的所有权。这有点让人头疼。 - Vatsal Manot
1
说编译器“信任”你是对编译器的误解。编译器保证,如果您取消引用无效的unowned引用,程序将立即崩溃。编译器唯一“信任”您(在假定您知道自己在做什么并且不生成安全检查的意义上)的时候是当您使用名称中带有unsafe的对象或函数时。 - rob mayoff
@robmayoff,你说得完全正确。我用词有些过于随意了。已经将其更改为更准确的内容。 - Vatsal Manot
1
这绝对是这篇帖子中最好的答案。+1 - NSNoob

3

unowned在合适的情况下(即确定该对象不会消失)实际上比weak更好,因为:

  • weak引用必须是可选类型,可能需要拆包,而

  • weak引用需要大量开销来跟踪引用,并将其更改为nil(如果它被释放),而unowned引用则不需要任何开销。


1

实际上这不是问题,因为目前为止,unowned 引用并没有创建任何强引用循环。当 Customer 对象被释放时,它的 CreditCard 也会立即释放。你的 CreditCard 将永远不会有机会引用已释放的 Customer


嗨,鲍勃。所以,如果我们设计的东西只有一个客户会持有给定信用卡的引用,那么一切都会顺利进行。这似乎是合理的。鉴于这种情况:如果信用卡对客户有强引用,最终结果不是一样的吗? - Verticon
谢谢,Bob。我现在明白了。当我们的代码设计保证使用unowned不会导致访问nil引用时,我们可以使用它。也就是说,设计保证当Customer被释放时,CreditCard也将被释放。 - Verticon

0

非常有趣的问题。以下是苹果公司文件中弱引用和无主引用之间的一些区别 (链接)

弱引用

弱引用是指不对其引用的实例保持强引用,因此不会阻止 ARC 处理被引用的实例。这种行为可以防止引用成为强引用循环的一部分。

无主引用

与弱引用类似,无主引用也不会对其引用的实例保持强引用。但与弱引用不同的是,当其他实例具有相同或更长的生命周期时,会使用无主引用。

你问题的答案:

weak 引用可能变为 nil,而 unowned 引用预计永远不会变为 nil,因此 weak 将是可选项,而 unowned 不需要是可选项。

在这种情况下,客户 可能有也可能没有 信用卡 但是没有 客户 的情况下不应该存在 信用卡

嗨Munahil。那么,信用卡具有对客户的未拥有引用和具有强引用之间的实际区别是什么? - Verticon

-1

好的,我终于明白了:

  1. 除了信用卡之外,对客户的最后一个引用被设置为nil。
  2. ARC检查客户的引用计数:
  3. 信用卡有一个强引用 - 客户的引用计数将为1,因此ARC不会释放它。结果 - 内存泄漏。
  4. 或者,信用卡有一个无主引用 - 客户的引用计数将为0,因此ARC将释放它。这样做会导致信用卡的引用计数变为0,从而导致其被释放。因此,信用卡将永远没有机会取消引用其现在为nil的无主引用。结果 - 没有崩溃。

因此,如果我们设计我们的代码,使得引用的持有者(信用卡)在引用的对象(客户)被释放时保证被释放,那么我们就有了无主引用被设计的情况。

感谢@Bob


如果在释放Customer时,其他东西仍然保留CreditCard,那么上帝保佑你永远不要触碰那个未拥有的指针。 - pronebird
安迪,你说得对。但是,我认为这里的重点在于我们设计了一些东西,使得你所说的情况不可能发生,因此我们有一个使用未拥有对象将很好地工作的情况。而且,如果我们某种方式违反了我们的设计,那么崩溃是一个好的结果。 - Verticon
罗伯特,在弱customer!上崩溃有些清晰且有保障。在未拥有的指针上崩溃就像是玩俄罗斯轮盘。内存释放时不会被归零,会产生副作用...如果你非常小心,并且所有东西都是按设计来的,那没问题,但这是一条很细的界线。 - pronebird
我相信人们只是在这个问题上投反对票。我的意思是答案已经有-1了... - SalvadorVayshun

-2

在这个主题上进行快速搜索,发现this链接指向另一个SO答案。

基本上,weak引用可以是nil,也可以不是;而unowned引用则假定它永远不会是nil

您可以在Apple文档中了解更多信息。

我猜测在这种情况下使用unowned的原因仅仅是因为假定unowned永远不会是nil(没有客户)。


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