Swift 中的弱者与无主。内部差异是什么?

weak vs unowned in Swift. What are the internal differences?

我了解 Swift 中 weakunowned 的用法和表面差异:

我见过的最简单的例子是,如果有一个 Dog 和一个 BoneBone 可能对 Dog (反之亦然)因为每一个都可以相互独立存在。

另一方面,在 HumanHeart 的情况下,Heart 可能具有对人类的 unowned 引用,因为一旦随着 Human 变成... "dereferenced",无法再合理地访问 Heart。那和带有 CustomerCreditCard 的经典示例。

所以这不是重复的问题。


我的问题是,有两个如此相似的概念有什么意义?本质上 99% 相同的事物需要使用两个关键字的内部差异是什么?问题是为什么存在差异,而不是差异是什么。

鉴于我们可以像这样设置一个变量:weak var customer: Customer!unowned 变量是非可选的优势是一个有争议的问题。

The only practical advantage I can see of using unowned vs implicitly unwrapping a weak variable via ! is that we can make unowned references constant via let.

...也许编译器可以出于这个原因进行更有效的优化。

这是真的吗,还是在幕后发生了其他事情,为保留这两个关键字提供了令人信服的论据(尽管细微的区别是——基于 Stack Overflow 流量——显然让新手和有经验的开发人员都感到困惑) .

我最想听听曾在 Swift 编译器(或其他编译器)上工作过的人的意见。

一个 weak 引用实际上设置为 nil,当引用对象解除分配并且一个 unowned 引用被设置为 nil 时,您必须检查它,但您不会被迫检查它。

您可以使用 if letguard? 等检查 weak 是否为 nil,但检查 unowned 没有任何意义,因为你认为那是不可能的。如果你错了,你就会崩溃。

我发现在实践中,我从不使用 unowned。性能损失很小,但使用 weak 带来的额外安全性对我来说是值得的。

我会将未拥有的使用留给需要优化的非常具体的代码,而不是一般的应用程序代码。

你正在寻找的 "why does it exist" 是 Swift 意味着能够编写系统代码(如 OS 内核),如果他们没有最多没有额外行为的基本原语,他们做不到。

注意:我之前在这个回答中说过 unowned 没有设置为 nil。这是错误的,一个裸 unowned 被设置为 nil。 unowned(unsafe) 未设置为 nil,可能是悬空指针。这是为了满足高性能需求,通常不应出现在应用程序代码中。

My question is, what is the point in having two such similar concepts? What are the internal differences that necessitate having two keywords for what seem essentially 99% the same thing?

它们完全不相似。他们尽可能地不同。

  • weak是一个非常复杂的概念,在引入ARC时引入。它执行近乎奇迹般的任务,允许您防止保留循环(通过避免强引用),而不会在引用的对象不存在时因悬挂指针而崩溃——这在 ARC 之前一直发生被介绍了。

  • unowned,另一方面,是non-ARC 弱(具体来说,它与非ARC assign).它 我们过去不得不冒的风险,它 在引入 ARC 之前导致如此多崩溃的原因。这是非常危险的,因为如果引用的对象不存在,您 可能会 得到悬空指针和崩溃。

差异的原因是 weak,为了创造奇迹,涉及 很多 额外的运行时开销,插入幕后编译器。 weak 引用是内存管理的。特别是,运行时必须维护一个 scratchpad 以这种方式标记的所有引用,跟踪它们,以便如果弱引用的对象不存在,运行时可以找到该引用并将其替换为 nil 以防止悬空指针。

在 Swift 中,因此,weak 引用总是指向一个 Optional(正是这样它可以被 nil 替换)。这是额外的开销来源,因为使用 Optional 需要额外的工作,因为它必须始终被解包才能完成任何事情。

因此,unowned 在适用的情况下始终是首选。但除非绝对安全,否则切勿使用它!使用 unowned,您 放弃了自动内存管理和安全性 。你是在故意回到 ARC 之前的糟糕日子。

在我的使用中,常见的情况出现在闭包需要涉及 self 捕获列表 以避免保留循环的情况下。在这种情况下,几乎总是可以在捕获列表中说 [unowned self]。当我们这样做时:

  • 对程序员来说更方便,因为没有什么需要解包的。 [weak self] 将是一个 Optional 需要解包才能使用它。

  • 它更有效,部分原因是相同的(解包总是增加额外的间接级别),部分原因是它是运行时暂存器列表跟踪的一个较少的弱引用。