我理解Swift中weak
和unowned
之间的用法和表面差异:
我见过的最简单的例子是,如果有Dog
和Bone
,则Bone
可能对Dog
有弱引用(反之亦然)因为每个都可以彼此独立存在。
另一方面,如果是Human
和Heart
,则Heart
可能会unowned
提及人类,因为只要Human
Heart
变为......"取消引用",无法再合理地访问Customer
。这是CreditCard
和weak var customer: Customer!
的经典示例。
所以这是不是一个问题的副本。
我的问题是,有两个这样相似的概念有什么意义?内部差异是什么,需要两个关键字,看起来基本上99%相同的东西?问题是为什么存在差异,而不是存在差异。
鉴于我们可以像这样设置一个变量:unowned
,unowned
变量不可选的优点是一个没有实际意义的点。
我可以看到使用
weak
vs通过!
隐式展开unowned
变量的唯一实用优势是我们可以let
通过customer-refunded-order.php
引用常量。
......也许编译器可以为此做出更有效的优化。
这是真的吗,还是在幕后发生了其他事情,为两个关键词提供了一个引人注目的论据(尽管略有区别 - 基于Stack Overflow流量 - 显然让新的和经验丰富的开发人员感到困惑)。 / p>
我最感兴趣的是听过那些使用过Swift编译器(或其他编译器)的人。
答案 0 :(得分:14)
我的问题是,有两个这样相似的概念有什么意义?内部差异有哪些必须使两个关键字基本上与99%相同?
它们完全不相似。他们尽可能地不同。
weak
是一个非常复杂的概念,在ARC推出时引入。它执行近乎神奇的任务,允许您阻止保留一个循环(通过避免强引用),而不会在引用的对象不存在时冒着悬空指针的崩溃 - 这种情况曾经发生在ARC之前的所有时间介绍了。
unowned
非 -ARC弱(具体来说,它与非ARC assign
相同)。在引入ARC之前,它是以前的风险,是造成如此多崩溃的原因。它非常危险,因为如果引用的对象不存在,可以获取悬空指针和崩溃。
差异的原因是weak
为了执行其奇迹,涉及运行时额外开销的 lot ,由编译器插入到幕后。 weak
引用是由内存管理的。特别是,运行时必须维护以这种方式标记的所有引用的 scratchpad ,并跟踪它们,以便在弱引用的对象不存在时,运行时可以找到该引用并将其替换为nil
以防止悬空指针。
在Swift中,因此weak
引用始终为可选(完全可以由nil
替换)。这是额外的开销来源,因为使用Optional需要额外的工作,因为必须始终将其解包以便完成任何操作。
出于这个原因,unowned
总是在适用的地方首选。但除非绝对安全,否则永远不要使用它!使用unowned
,您丢弃自动内存管理和安全性。你故意回到ARC之前的旧日。
在我的用法中,常见的情况是在闭包需要一个涉及self
的捕获列表以避免保留周期的情况下。在这种情况下,几乎总是可以在捕获列表中说[unowned self]
。当我们这样做时:
对于程序员来说更方便,因为没有什么可以打开的。 [weak self]
是一个可选的,需要展开才能使用它。
它的效率更高,部分原因相同(解包总是会增加一个额外的间接级别),部分原因是因为它只是运行时暂存器列表中较少的弱引用来跟踪。< / p>
答案 1 :(得分:8)
weak
引用实际上设置为nil,你必须在引用解除分配并且unowned
设置为nil时检查它,但你不必强制检查它。
您可以使用weak
,if let
,guard
等检查?
与nil的对比,但检查unowned
是没有意义的,因为你认为这是不可能的。如果你错了,你会崩溃。
我发现在实践中,我从不使用无主。有一个微不足道的性能损失,但使用弱的额外安全性是值得的。
我会将无用的用法留给需要优化的非常具体的代码,而不是一般的应用代码。
您正在寻找的“为什么存在”是Swift意图能够编写系统代码(如OS内核),如果他们没有最基本的原语而没有额外的行为,他们可以不这样做。
注意:我之前曾在这个答案中说过,无主并未设定为零。这是错误的,裸unowned
设置为零。 unowned(unsafe)
未设置为nil,可能是悬空指针。这是为了满足高性能需求,通常不应该在应用程序代码中。