斯威夫特的弱势与无足。内部差异是什么?

时间:2017-03-16 18:40:30

标签: swift compiler-optimization weak-references memory-safety

我理解Swift中weakunowned之间的用法和表面差异:

我见过的最简单的例子是,如果有DogBone,则Bone可能对Dog有弱引用(反之亦然)因为每个都可以彼此独立存在。

另一方面,如果是HumanHeart,则Heart可能会unowned提及人类,因为只要Human Heart变为......"取消引用",无法再合理地访问Customer。这是CreditCardweak var customer: Customer!的经典示例。

所以这是不是一个问题的副本。

我的问题是,有两个这样相似的概念有什么意义?内部差异是什么,需要两个关键字,看起来基本上99%相同的东西?问题是为什么存在差异,而不是存在差异。

鉴于我们可以像这样设置一个变量:unownedunowned变量不可选的优点是一个没有实际意义的点。

  

我可以看到使用weak vs通过!隐式展开unowned变量的唯一实用优势是我们可以let通过customer-refunded-order.php引用常量。

......也许编译器可以为此做出更有效的优化。

这是真的吗,还是在幕后发生了其他事情,为两个关键词提供了一个引人注目的论据(尽管略有区别 - 基于Stack Overflow流量 - 显然让新的和经验丰富的开发人员感到困惑)。 / p>

我最感兴趣的是听过那些使用过Swift编译器(或其他编译器)的人。

2 个答案:

答案 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时检查它,但你不必强制检查它。

您可以使用weakif letguard等检查?与nil的对比,但检查unowned是没有意义的,因为你认为这是不可能的。如果你错了,你会崩溃。

我发现在实践中,我从不使用无主。有一个微不足道的性能损失,但使用弱的额外安全性是值得的。

我会将无用的用法留给需要优化的非常具体的代码,而不是一般的应用代码。

您正在寻找的“为什么存在”是Swift意图能够编写系统代码(如OS内核),如果他们没有最基本的原语而没有额外的行为,他们可以不这样做。

注意:我之前曾在这个答案中说过,无主并未设定为零。这是错误的,裸unowned设置为零。 unowned(unsafe)未设置为nil,可能是悬空指针。这是为了满足高性能需求,通常不应该在应用程序代码中。