Chris Lattner 访谈录(上)

by admin on 2020年3月18日

在上周发布 4.2
正式版本后,Swift
开发团队本周在官网更新了 “Swift 5.0 Release
Process” ,主要介绍 Swift
5.0 的开发目标、发布流程和预估时间表。

音频:ACCIDENTAL TECH PODCAST 205原文:PEOPLE DON’T USE THE WEIRD
PARTS本文首发杂志链接:《iOS成长之路》- 2017夏

图片 11
.png

和我们之前报道的一样,Swift 5.0
的主要目标是使语言实现 ABI
稳定性。同时,模块稳定性也是重点工作,根据开发进度在 Swift
5.0 或在之后的 5.x 版本中实现。

  • Chris Lattner 是谁?
  • Xcode 的编译器 LLVM 背后有怎样的故事?
  • Swift 诞生的前世今生,封闭的苹果为何要拥抱开源?
  • 说好的 ABI 稳定性何时能推出?

Swift每半年有两个重大更新的版本,4.1和4.2就是继4.0之后2018年的两个版本。Swift
4.2版本主要有两方面的更新,一是关注提升开发人员生产力,你可以看到项目构建速度的提升,利于开发的语言改进;二是在二进制兼容性方面做出了大量的努力。

不幸的是,Swift 5.0 与早期的 Swift
版本依然不是二进制兼容的。不过,开发团队表示,后续的 Swift 版本将与
Swift 5 二进制兼容。

图片 2

苹果希望在所有平台上支持Swift,大概一个月前,苹果扩展了公共持续集成系统,现在可以无缝插入自己的硬件支持,以便在那里进行测试。

在源兼容性方面,Swift 5 编译器将能够接受使用 Swift 4.2
版本编写的代码,但是不与 Swift 3 模式兼容。Swift 4.2 是最后一个支持
Swift 3 模式的版本。

教育背景

  • 伊利诺伊大学 PHD

图片 32
.png

图片 4

工作经历

  • 2005年 – 2017年供职苹果,前开发部高级总监,架构师
  • 2017年开始,担任特斯拉副总裁,负责自动驾驶

六个月前,Swift社区从邮件列表转向论坛,可以让大家更方便的参与讨论。

至于发布时间,开发团队表示,按计划2018年11月16日将是最后一次合并更改,之后会进入一个“烘焙”期,仅对一些重要的东西进行修复。待一切就绪后,将迎来正式版。

主要成就

  • Swift 之父,主要作者
  • LLVM 之父,主要作者
  • Clang 主要贡献者

图片 53
.png

(文/开源中国)    

荣誉

  • 2016年被评为“创造未来的25位当世天才”
  • 2013年获得 ACM 系统设计大奖

在Swift 4.2版本更新中,有4个主要内容:

自我介绍

1. 你怎么看待自己?

我是个程序员。我喜欢写代码。我编程有很长时间了。

我在读博的时候就开始写 LLVM 了。当时 LLVM
是我的博士研究项目,我想把它做成工业界中颠覆性的产品。当时我异想天开,尝试了各种架构设计,想解决以往编译器所有的弊端
— 结果当然没有如愿。我毕业后,就希望能接着搞 LLVM
,当时只有苹果允许我入职之后继续设计并实现 LLVM
。我想都没想就加入了苹果。

  • 更快的编译速度
  • 新的语言特性提高效率,移除样板代码
  • Swift的SDK改进
  • 改进二进制兼容性

LLVM

2. 说说 LLVM(Low Level Virtual Machine)到底是什么吧

  • 先说编译器:编译器是把程序员的代码翻译成机器可以理解的语言的工具;
  • 再谈 LLVM:一个模块化和可重用的编译器和工具链技术的集合,Clang 是
    LLVM 的子项目,是 C,C++ 和 Objective-C
    编译器,因为多模块的复用,所以提供了惊人的快速编译,比 GCC 快3倍。

3. LLVM
是一开始就作为一个完整的编译工具来使用的吗?还是有什么其他故事

LLVM 当时是为了解决一个小问题而开发的:当使用OpenGL 函数库的时候(Mac OS
10.4 和
10.5环境下),比如你要调用这个函数,glVertex3f(),编译器必须将其转化为特定的GPU可以理解的数据。但是这带来一个问题:市面上有海量的GPU,每个GPU的性能和参数也不尽相同,所要求的数据格式也不同。这时
LLVM 可以产生很小的一部分代码去解决这个问题,这是 LLVM 诞生的初衷。

4. LLVM 的 bytecode 和 Apple 现在的 bitcode 有什么不同?

这是历史遗留问题。一开始 LLVM 是开源的,所有代码在转成二进制时就叫做
bytecode — 因为 java
当年就是这么叫的。当时这一部分有很多问题:比如不能扩展,无法兼容,非常脆弱。

然后就到了 LLVM 2.0,当时我重新设计了架构,采用的就是 Bitcode 机制。LLVM
2.0 将所有代码以比特流(bit stream)而不是字节流(byte
stream)的形式来编码。这就是 bitcode 这一术语的由来。

主要的工作流程就是现将代码转成比特流,然后相应处理。处理完后再将编码传到其他地方去。

5. Bitcode 这个机制比直接传输二进制有什么好处

好处那是多了去了。首先
编译器工作起来会越来越好。因为通过Bitcode机制,它可以通过编译不同代码来存储各种优化方法,这样下次碰到类似代码,它就会自动启动相关优化机制,使得效率提升。还有个好处是
LLVM 可以让芯片的兼容性变得很好。因为 Apple
每年都在芯片上推陈出新,它们转化为二进制的规则都不尽相同,LLVM
只要每次重新编码并传输成比特流就好了。

当然 Bitcode 也不是万能的。比如它不能解决 32位的 APP
在64位机器上的兼容问题。这个问题其实应该依靠代码逻辑。

Swift
5版本将在2019年初发布,在这个版本里,二进制兼容性将会稳定下来,意味着编译完的二进制文件可以和其他编译器构建的代码进行互操作,这对于语言的成熟度来说是具有里程碑意义的,将使得苹果能够直接在操作系统中发布Swift运行时,而不需要再包含在App里面,对应用启动速度,运行效率,和对减少应用大小都有很大帮助。

谈管理

6. 在职业生涯中,你在 LLVM
上鞠躬尽瘁,但我们发现这几年你更多的工作是在管理上,你自己怎么看这种转变的?

我虽然做管理了,但是我依然喜欢写代码,而且我每天都写,因为我就是个极客嘛。而且,其实我很早就开始做管理的工作了。不过我一直是作为技术领导人的角色带
2 到 3 个人的,我只是在写代码方面把把关,给他们提提建议这样。

后来带的人多了,队伍也大了。我不仅管程序员,还管小组经理和其他技术领导人。虽然我一直喜欢写代码,但是管理对我来说是一个必须要去做的事。现在回过头来,我觉得干得还不错。跟大家一起工作之后我知道很多事协同工作效果更好,和同事交流你就会理解他们的想法,这样我就可以制定更好的计划路线。

其实我没感觉整个过程有什么不同。直到今天我还夜以继日、废寝忘食得写代码,我并不是坐那边动动嘴皮子,指挥别人干活的老板。我其实每个周末都在写代码,我很忙的。

图片 64
.png

Swift

7. Swift
是如何诞生的?在苹果这样一个大厂,决定做出如此巨大的变革,同时还是在封闭的环境下,你是如何一步步实现的?

首先,苹果内部所有的项目都不尽相同 —
工作流程、战略规划、实施细节,到最后发布。Swift
也一样,没有可比性。因为苹果本身就是小组单兵作战模式 —
每个组负责不同的大方向,组里自己计划和工作,甚至招人都是各自招。

言归正传,契机发生在2010年了。当时好像是我们刚刚完成了 Clang 对
C++的支持。你也知道 C++ 写起来有多丑,但是做个编辑器支持 C++,完善 C++
这门语言就是另一回事了,我们当时搞了好久终于完成的时候特别有成就感。当然
Clang 远没有到达完美的地步。

我又扯远了。除了做 Clang 以外,无论是 C语言,C++,还是
Objective-C,都有一些我不是很满意的地方。所以我就想要不我们搞个新的语言来吧。新的语言要越简单越好。一开始大家都没认真,后来我跟很多同事聊了之后觉得新语言的计划可行,而且大家都很亦可赛艇。于是我们就用业余时间开始顶层设计和写代码。

现在问题来了,因为我们已经有 Objective-C
了。虽然它有几个地方很丑,比如老是用
“@”,每句结束了还要打分号,但是这些并不妨碍它是一门伟大的语言。所以,我们为什么要开发新语言,而不是把精力花在优化
Objective – C 上?

图片 7

原因有三。

第一,如果我们大幅优化 Objective – C,把很多 Swift
的特性加进去,这对开发者来说是灾难性的,因为他们要对原来的 APP
要进行大幅修改;

第二,Objective – C 很多特性积重难返,比如它安全性上的问题;

第三,Objective – C 是基于 C 开发的语言,所以你无论怎么优化,它必然有 C
语言自身的缺陷。

于是我们就动手做 Swift 了,它的背后有着数百人的努力: 支持 Xcode,开发

代码兼容性

Xcode 10包含一个Swift 4.2编译器,这个编译器兼容Swift 3, Swift 4。但Xcode
10是支持兼容Swift 3的最后一个版本。

图片 85
.png

Playground,兼容调试器和编译器。我个人感到最骄傲的一点是,我们并不打算自己内部把它做到完美

我们开源、我们依靠社区,这样一门语言才能在无数开发者的实战中得到检验和改进,我想这才是
Swift 最棒的地方。

8. 你之前在优化 Objective-C 的时候,有没有想到什么地方是未来 Swift
可以用得到的?

ARC。我们其实一直都在争论是用垃圾回收机制(garbage collection)还是
ARC,后来决定了是 ARC。

另一个是模块化,我们也将这一部分的经验带到了 Swift 开发中。

其实,很多数组和字典方面的语法优化本来是计划在 Objective – C
上面的。但是后来我们开发了
Swift,于是这些改进被直接用在了新语言上,所以大家会在写 Swift
的时候觉得似曾相识,因为本来这些就是 Objective-C 的升级版本嘛。

我可以透露一个有意思的事情。我们在做 Swift 的时候,很多 iOS
开发者,包括苹果内部的工程师,都在吐槽我们这几年在 Objective – C
上毫无建树,都在说你们为什么不做这个那个。我们当然不能告诉他们我们在全力开发
Swift,而他们所要的语法功能我们都会给。

9. 苹果内部对于 Swift 的使用情况和开发是怎么看得?

Swift
团队对于开发上有明确的目标和计划,应用二进制接口的稳定性一直是我们的首要目标。很多人很喜欢我们开源的
Swift Playground。同时 iOS 系统内置的 Music App 也是 Swift
写的。其实用不用 Swift
主要是技术和开发方面的考量,苹果内部同时得兼顾稳定性和开发效率,这不是说大家喜不喜欢这个语言的问题。

Swift 刚发布的时候,内部很多组都很惊讶:我们已经有了
Objective-C,为什么还要搞新的 Swift?而且 Objective-C
本身就很不错,开发起来也很顺手。后来渐渐 Swift
成熟了,大家也爱上了这个新生儿。

内部其实对于 Swift
一个很大的顾虑在于,苹果的所有开发必须兼容32位机器,而32位的应用都采用了
Objective-C 的 runtime 机制。这就要求 Swift
团队也弄出个类似的机制,或者弄个兼容的方案,否则 Swift 无法与 AppKit
适配。

10. 开源后的 Swift 发展态势喜人,你对此有什么看法?

开源之后,Swift 发展之好让我咋舌,然而这也是问题所在。

当年我们开源了 LLVM 和 Clang,它们也发展喜人。我们的对手 AMD
们完全跟不上我们。但是跟 Swift 比起来,它们的发展也太慢了,LLVM 和 Clang
开源后完全没有 Swift 这么火。

Swift 就不同了,开源一年之后,我们就有了上百万的开发者在使用这门语言 —
我和很多有丰富开源经验的老工程师都吓了一跳,这简直了!然后我们每天收到无数的邮件和
pull
requests,要求更新这个、要求优化那个,我们的节奏完全被打乱了。我们如何规划开发?我们如何把
Swift
的开发导向一个正确的方向?这些问题随着时间的推移和经验的积累,慢慢找到了解决之道。

我现在觉得开源这个决定至关重要。一来大家会帮着优化;二来我们有个巨大的论坛,在那里大家可以畅所欲言,全世界的人都在帮着
Swift
进步,这真的很棒。我们虽然没有一开始就具体计划要开源,但是苹果内部当时都觉得
Swift 肯定有一天要开源。

编译器改进

Swift
4.2在编译Swift代码速度上有了3倍的提升。在大部分项目中,编译速度将提高2倍,这取决于你的项目中Swift代码所占的比例。以往被大家所诟病的Swift编译龟速,总算引起苹果重视了。

图片 96
.png

Xcode10 从Optimization Level分离出Compilation Mode,Compilation
Mode可选值如下图,建议在Debug模式下开启增量模式(Incremental),以提高编译速度,而在Release下开启全量模式(Whole
Module)。

图片 107
.png

而Optimization Level新增了Optimize for
Size,大部分项目在开启这个模式后,Swift代码生成的二进制文件减少了10%到30%,但是运行时的性能变慢了5%。如何你的项目对应用包大小比较重视,可以考虑开启这个模式。

图片 118
.png

苹果与特斯拉

图片 12

11. 苹果好像一直是个封闭的公司,你们内部对于开源怎么看?

苹果其实有开源的传统。 LLVM
虽然不是始于苹果,但是最终是苹果完成并将其开源。Clang
则完完全全是生于斯开源于斯。还有其他工具,比如
LLDB,libc+,以及compiler-rt 都是如此。

所以对于 Swift 来说,开源只是时间问题。当年从 Swift 1.0 到 Swift
2.0,一切都乱七八糟。当时我们重点在开发错误处理机制,还有协议、拓展等一系列重要的功能。所以开源
Swift
1.0,并不是一个好选择,因为这些重要的东西都没有,而这些开发是当务之急。当
Swift 2.0
到来的时候,我们才有空去开源、去做社区拓展和论坛搭建。开源社区可以帮我们修复细节,我们这时候可以更多的投入在架构设计上。

12. 苹果最让你怀念的是什么?

苹果是这样一个公司,你可以选择你喜欢的东西,然后努力工作去实现它,最终你的工作会落实在产品上,影响亿万计的人。

有很多公司,你可以努力工作,但是不一定能做你喜欢的东西;你做出来东西,可能会被束之高阁;你做的产品,也许最后很幸运的发布,但是并不一定有很多人会用。在苹果,你的工作可以真正改变世界,很有成就感。

13. 你觉得到特斯拉之后,还会努力为 Swift 做出贡献吗?

特斯拉的工作非常有挑战性,这是我最开心的地方。我现在还没入职,所以也不知道我之后对
Swift 能做多少工作。也许我还会夜以继日的发 Pull
Request,也许我就周末写写 Swift 代码。我应该会从各个方面 —
无论是顶层设计还是具体代码实现,与苹果的核心团队合作,为这个语言做贡献。

其实我一直想说,Swift
只是我在苹果工作的一小部分,我花了大量的时间在其他事情上。实际上在苹果我也就晚上或者周末有空写写
Swift
。我希望到了特斯拉之后我还能花同样的精力和时间在 Swift
上,毕竟我对这门语言统治世界充满期待。

运行时优化

Swift也是使用和Objective-C是一样ARC方式管理内存的。Swift
4.1及以前的版本,ARC以”Owned”方式自动插入Retain和Release,调用方负责
Retain,被调用方负责Release。容易出现多个额外相互抵消的Retain-Release,造成性能的浪费。

func caller() { // ‘x’ created with +1 reference count let x = X() // retain x bar // release x in callee // retain x baz // release x in callee foo // release x in callee}

Swift
4.2则改成以”Guaranteed”方式插入Retain和Release。由调用方管理对象的生命周期,不再是被调用方负责Release。这个优化减少了无用的Retain、Release代码,提升了性能,减少了一部分二进制文件的大小。

func caller() { // ‘x’ created with +1 reference count let x = X baz // release x}

ABI 稳定性

14. 现在 Swift
已经到了第3个版本了。我们也知道ABI稳定性的追求一直是你们的目标,但是它也一直被各种事情拖延。你对此有什么计划吗?或者说你从拖延中学到了什么经验教训吗?

ABI 推迟有两个原因。

第一是因为 Swift 的开发进程中有很多不确定性。当 Swift
开源之时,一堆人对我们提 pull request,提各种各样的
issue。这样我们就不得不去花大量的时间去维护开源社区,而不是专心去做计划内的工作。

第二个原因是,尽管稳定的 ABI 很重要,但是对于开发者来说,稳定的 ABI
对他们来说没有明显的好处,他们更关心是语法和兼容上的稳定和优化。所以我们后来修改了计划,语法和兼容上的稳定性被定为是最先要实现的目标。这样当
Swift 3.1 或者 Swift 4.0 出来的时候,大家不用担心语言上的转化会让 Xcode
崩溃,或是需要大家整个重构 APP。Swift 3.0 主要就是实现这个目标。

图片 13

15. 稳定的 ABI 什么时候推出?他会赶在异步和并发模型之前吗?

Swift 现有的内存管理机制对 ABI
稳定性造成了不小的影响。有些底层逻辑还需要调整,比如 getter 和 setter
的生成以及属性的内存分配问题,苹果内部正在做这件事,这之后我们才能完成
ABI。至于并发模型啥的就跟 ABI 没有关系了。

很多人担心 Swift 4.0 的时候苹果能不能推出稳定的
ABI,因为毕竟工作量太大。ABI
的工作正在井然有序得进行,而且对于开源社区来讲推出稳定的 ABI
至关重要。Ted (Chris Lattner 之后的 Swift 领导人)有一件事说对了,现在
Swift 当务之急就是让编译器更稳定,让错误处理更方便,提高编译速度,并且将
Swift 拓展到大规模系统中。

我在想 Swift 4.0 的时候究竟能看到什么。也许没有稳定的
ABI,但是一定会有重要的新功能加入。

ABI 将允许未来 Swift 版本开发的应用程序和编译库可以在二进制层次上与
Swift 3.0
版本的应用程序和编译库相互调用。这样,ABI的稳定性将保证一定程度的二进制兼容性,并且第三方更容易发布二进制库。另外,ABI
将允许删除需要的 Swift 标准库和二进制文件,就像目前情况下通过Xcode创建的
iOS 和 OS X 应用程序一样。

图片 14LLVM.png

补充:LLVM的三层结构

  • 第一层:Clang 编译器,负责编译各种语言
  • 第二层:代码优化器,通过模块化操作优化代码,是 Bitcode
    逻辑的主要部分
  • 第三层:代码翻译器,针对不同平台和 GPU 将代码翻译成机器语言

补充:LLDB,llbc++,compile rt

  • LLDB: 一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB
    绑定在 Xcode 内部,存在于主窗口底部的控制台中;
  • libc++,libc++ ABI: 高性能 C++ 标准库实现,支持 C++ 11
  • compiler-rt:为 LLVM 和 Clang 设计的编译器扩展函数库。针对
    __fixunsdfdi 和其他目标机器上没有一个核心 IR (intermediate
    representation)
    对应的短原生指令序列时,提供高度调优过的底层代码生成支持。

ABI 是什么?

Application Binary Interface,中文名:应用二进制接口。是 APP 和
操作系统、其他应用之间的二进制接口。它包括以下细节:

  • 数据类型的大小、布局和对齐;
  • 调用约定(控制着函数的参数如何传送以及如何接受返回值),例如,是所有的参数都通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先push到栈上还是最后;
  • 系统调用的编码和一个应用如何向操作系统进行系统调用;
  • 以及在一个完整的操作系统ABI中,目标文件的二进制格式、程序库等等。

Chris Lattner’s Homepage深入剖析 iOS 编译 Clang LLVM与调试器共舞 – LLDB
的华尔兹compiler-rt” runtime libraries应用二进制接口

Small String

Swift
4.2在64位机器上,字符串的编码由24bytes改为16bytes,并且对于足够小的字符串,将直接存进这16bytes,而不需要分配堆内存,提高性能,减少内存占用。

枚举遍历

Swift
4.1及以前的版本并没有提供遍历枚举的方法,所以遍历枚举往往需要事先手动管理一个包含所有枚举项的数组,这种方法不仅繁琐,在后续迭代中,如果要新增枚举项,容易忘记添加进allCases。

enum Gait { case walk case trot case canter case gallop static var allCases: [Gait] = [.walk, .trot, .canter, .gallop]}for gait in Gait.allCases { print}

Swift 4.2 新增了 CaseIterable 协议,遍历枚举变得方便简单

enum Gait: CaseIterable { case walk case trot case canter case gallop}for gait in Gait.allCases { print}

Conditional Conformance

首先,我们看下面Swift 4.0的代码

extension Sequence where Element: Equatable { func contains(_ element: Element) -> Bool}let animals = ["cat", "dog", "weasel"]animals.contains // OKlet coins = [[1, 2], [3, 6], [4, 12]]coins.contains // Error

这是因为在Sequence有contains的方法,元素是Equatable时,我们就可以通过contains方法判断是否包含该元素,而当元素是[Int]时,[Int]不是Equatable(在Swift
4.0及以前),所以调用contains方法时会编译出错。

但是如果一个集合的元素都是Equatable的,那么我们就应当认为该集合也是Equatable的,因为我们可以便利所有元素去判断集合是否相等。在Swift
4.0及以前,可以通过给集合加扩展实现,而Swift
4.1之后,只要元素是Equatable的,则集合也默认是Equatable。

同理的还有其他协议如Hashable、Encodable、Decodable,甚至是自定义的协议。

let coins = [[1, 2], [3, 6], [4, 12]]coins.contains // This now works!

Equatable和Hashable自动合成

在Swift
4.0,要比较两个结构体是否相等,需要手动实现==方法,同时列出所有属性来判断相等。当新增一个属性时,还需要记得手动更新==方法,容易出错。

struct Restaurant { let name: String let hasTableService: Bool let kidFriendly: Bool}extension Restaurant: Equatable { static func ==(a: Restaurant, b: Restaurant) -> Bool { return a.name == b.name && a.hasTableService == b.hasTableService && a.kidFriendly == b.kidFriendly }}

而Swift
4.1仅仅只需要声明该结构为Equatable,将自动生成==方法,比较所有属性。

struct Restaurant: Equatable { let name: String let hasTableService: Bool let kidFriendly: Bool}

同理,Hashable也支持自动合成代码。

Hashable功能增强

对一个结构体实现Hashable,往往是手动书写hashValue的实现,而这种实现难以理解,容易出现问题,其次,这种实现往往不够高效,在Dictionary和Set中使用有性能问题,同时,也不够安全,容易被黑客利用。

struct City { let name: String let state: String let population: Int}extension City: Hashable { var hashValue: Int { return (name.hashValue &* 58374501) &+ state.hashValue }}

所以Swift4.2提供了生成hashValue的方法来解决这个问题

extension City: Hashable { func hash(into hasher: inout Hasher) { name.hash(into: &hasher) state.hash(into: &hasher) }}

需要注意的是,苹果自带的Hash值生成算法,使用了随机数种子来加密Hash值,每个进程拥有一个随机数种子,在应用启动时生成。意味着,相同的内容在应用重启后或者不同的进程里计算的到的Hash值是不一样的。
如果业务对Hash值有比较强的依赖,需要保证每次生成的Hash值一样,可以在Xcode的环境变量里设置变量SWIFT_DETERMINISTIC_HASHING=1,来关闭使用随机数种子。

生成随机数

在Swift
4.1及以前的版本,通过C语言生成随机数,使用这种方法有两个问题,一是需要引入Foundation,而且Foundation在Linux系统下不支持,二是得到的随机数不是均匀分布的,例子中,1到4出现的概率比5和6大

let x = 1 + Int(arc4random //range 1...6

Swift 4.2为了解决这些问题,对数值类型新增了random方法实现获取随机数。

let intValue = Int.random(in: 1 ..< 6)let floatValue = Float.random(in: 0 ..< 1)

此外,还对集合提供了randomElement方法获取随机元素,shuffled方法对数组“洗牌”,打乱顺序。

let greetings = ["hey", "hi", "hello", "hola"]// 注意randomElement方法返回值是可选值print(greetings.randomElement // 打乱数组从未如此简单let randomlyOrderedGreetings = greetings.shuffled()

新的编译条件

Swift 4.2新增了canImport,hasTargetEnvironment的编译条件来优化像 || os
|| os && || cpu
这种长串、不易读、目的又不明确的编译条件。使用Swift跨平台开发的建议使用。

// Before#if  || os || os &&  || cpu...#endif// Now#if hasTargetEnvironment(simulator)...#endif

Implicitly Unwrapped Optionals改动

在Swift
4.2,IUO不再是一个Type,而是一个变量声明的标记,编译器将带标记的变量的类型检查为可选值,当使用到该变量时,先给这个变量加上强制解包,再检查类型。

let x: Int! = 1 // x 被标记为IUO,类型其实还是可选值let y = x + 1 // 实际上编译时,编译器会转化为 x! + 1 去进行编译

因为IUO不再是一个Type,下面的代码将会导致编译时错误:

let array: [Int!] = [] // 编译不通过而当将创建IUO的别名时,会得到一个警告,同时别名实际上只是可选值类型。typealias T = Int! // 将会得到警告let array: [T] = [3] // array为[Int?]类型

强制内存独占访问

在Swift
4及以前的版本,新增了内存独占访问检查的特性。它是编译时和运行时检查的组合,它们限制某些操作被执行,特别是禁止重复访问相同的内存位置。比如下面的例子:

struct Path { var components: [String] = [] mutating func withAppended(_ name: String, _ closure: () -> Void) { components.append closure() components.removeLast() }}var path = Path(components: ["usr", "local"])path.withAppended { print // 这里的path与上面的path造成独占访问冲突}

Swift可以在编译时检查到这种错误。Swift
4.2改进了这种检查,可以在更多情况下捕获这种错误。

4.2版本带来了ABI稳定性的提升,一部分新的特性,提高开发效率,值得升级。而Apple将4.2描述为“在Swift
5中实现ABI稳定性的中继点”,希望Swift 5能带来更稳定的ABI。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图