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

eph*_*mer 15 weak-references compiler-optimization memory-safety swift

我理解的使用和肤浅的差异weak,并unowned在斯威夫特:

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

在另一方面,在的情况下HumanHeart,则Heart可能有一个unowned人类的参考,因为一旦Human变成......"引用",将Heart不能再合理地进行访问.那和经典的例子一起CustomerCreditCard.

所以这不是问题的重复.


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

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

我可以看到使用vs隐式展开变量via 的唯一实际优点是我们可以通过引用使引用保持不变.unownedweak!unownedlet

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

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

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

mat*_*att 15

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

它们完全没有相似之处.它们尽可能地不同.

  • weak这是一个非常复杂的概念,在ARC推出时引入.它执行近乎神奇的任务,允许您阻止保留一个循环(通过避免强引用)而不会在引用的对象不存在时冒着悬空指针的崩溃 - 这种情况曾经发生在ARC之前的所有时间被介绍了.

  • unowned另一方面, -ARC较弱(具体而言,与非ARC相同assign).这我们曾经有过的风险是什么,这什么原因导致这么多的崩溃,引入了ARC之前.这是非常危险的,因为你可以,如果被引用的对象熄灭存在获得一个悬摆指针和崩溃.

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

因此,在Swift中,weak引用始终是一个Optional(完全可以替换为nil).这是额外的开销来源,因为使用Optional需要额外的工作,因为必须始终打开它才能完成任务.

因此,unowned无论何时适用,始终是首选.但除非绝对安全,否则永远不要使用它!有了unowned,你就丢掉了自动内存管理和安全性.你故意回到ARC之前的旧日.

在我的使用,通常情况下发生在封闭需要的情况下捕获列表包括self为了避免保留周期.在这种情况下,几乎总是可以[unowned self]在捕获列表中说出来.当我们这样做时:

  • 这对程序员来说更方便,因为没有什么可以解开的.[weak self]将是一个可选的需要展开才能使用它.

  • 它的效率更高,部分出于同样的原因(解包总是增加额外的间接级别),部分原因是因为它只是运行时的暂存器列表中较少的弱引用来跟踪.

  • 您只需要想象ARC在幕后完成所有记账工作需要什么.这个过程在引入ARC的精彩WWDC 2012视频406中得到了很好的描述.每个人都应该观看这个视频,因为Swift ARC是Objective-C ARC(事实上,我们现在知道Chris Lattner为Objective-C发明了ARC,这样他就可以创建Swift). (3认同)

Lou*_*nco 8

一个weak参考实际上被设为零,你必须检查它当指涉解除分配和unowned一个被设置成零,但你不会被强迫检查.

您可以检查weak对比零if let,guard,?等,但它是没有意义来检查unowned,因为你认为那是不可能的.如果你错了,你会崩溃.

我发现在实践中,我从不使用无主.性能损失微不足道,但使用弱电的额外安全性对我来说是值得的.

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

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

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