查看原文
其他

Swift 5.3的进化:语法、标准库、调试能力大幅提升

蒋志远(星志) 淘系技术 2021-08-11
Swift 从 5.0 的 ABI 稳定到5.1 的模块稳定,Swift 终于不是《Swift 入门到重学》了。本次 WWDC2020,Swift 5.3 正式发布,Swift 依旧朝着安全、高效、易读的方向持续发力,不断的在改进语法,增强代码的表达能力和易用性。因为 Swift 的模块稳定,SPM 现在也支持了二进制模块的分发,逐渐完善的社区生态也在不断拓宽 Swift 可以涉足的领域,而不仅仅是在 Apple 平台之上。



Swift 发展里程碑



下图展示了 WWDC2020 中 Swift 相关内容的脑图,希望可以帮助大家快速了解。




语言环境的完善和拓展


一门完善编程语言有三个最基本的要素:语法、标准库、调试能力。语法设计决定了语言的编程范式;标准库决定了语言的基本能力;调试能力决定了开发者的体验和语言的稳定性。


苹果在 Swift 的迭代过程中不断的强化这几点,我们可以来看看 Swift 又得到了哪些提升。



语法特性



Swift 的语法设计核心还是 OOP,但是这不妨碍 Swift 的语法在支持 POP 和函数式编程甚至 DSL 得到的强化。Swift 也因为 SDL 特性的加入,开始逐渐的适应声明式编程的方向发展,比如后文提到的 @main 等等。


 Multiple trailing closure



这个改进解决了当函数最后几个参数为闭包的情况下,导致的括号嵌套的问题,API 更加简洁也更加具有表达性。SwiftUI 利用这个语言特性,也变得更加简洁易懂。


 KeyPath as Function


KeyPath<Target, Value> --隐式转换--> (Target) -> Value

现在 KeyPath 可以当做函数来使用了。这个语法糖解决的问题当我们使用类似 map 一样的函数时,只需要取出对应数据模型中的某一个属性,为此我们不得不写类似 map { $0.property } 的代码,有了这个语法糖,事情就可以简化成了 map(\.property)。


 Type-based program entry point (@main)


引入了新的修饰符 @main,可以标记在带有 public static func main() 函数实现的所有类型,无论 main 函数时从拓展来得还是继承来的。添加这个特性的意义在与维持声明式的语义,将声明式语义进行到底。YES!


 Increase availability of implicit self in closures


以前我们写逃逸闭包时如果捕获了 self,我们需要在跟 self 有关的地方写上 self. 以警示我们注意循环引用。



如果在闭包的捕获列表中显示声明捕获 self,在闭包中对 self 相关的访问可以省略。如果是在不可变的函数中访问,self 可以直接省略(为了 SwiftUI)。



其实这一点改进有用但是覆盖面并不是很广,因为在实际的应用中,我们都是尽量先弱引用 self 后再强引用 self,来保证 self 的可访问性。在如下场景就得不到此项优化:


requestDataAsync { [weak self] in guard let self = self else {return} self.property // ✅ property // ❎ 需要显式声明 self}

 Multi-pattern catch clauses


这种写法可以自动实现错误匹配,进入到对应的错误处理中,而不需要使用 switch,增强语言的可读性。



 Enum enhancements


自动符合 Comparable


编译器现在可以自动为你生成 Comparable 的相关方法,实现 Enum 的比较。



Enum case 可以用来适配 protocol


这个特性看引用场景需要吧,官方给了一个比较好的例子。具体相关内容可以参考 SE-0280。



 DSL 新增对 switch 的支持


现在可以在 SwiftUI 等 Swift DSL 中使用 switch-case 来进行模式匹配,之前只有对 if-else 的支持。某种程度上也是为 SwiftUI 而生的能力。




标准库



其实这里说标准库是广义的标准库,其中包括了开发者随语言分发的标准库,如标准 I/O 库等,运行时环境,编译环境,一方库等等。苹果今年在这部分下足了功夫,因为标准库、各种各样的一方三方库才是展现一门语言能力的地方,否则再好的语法也不会有人用,语言终究还是工具,能解决问题才是关键。


Swift 5.3 在代码尺寸和运行时都有不小的提升。Swift Package Manager(SPM)增加对二进制和资源的支持,深度集成 Xcode,亲儿子的优势逐渐显示了出来。Swift 本来设计的初衷本来就是一门 General Purpose 的语言,今年苹果正式宣布 Swift 支持了 Apple platform,Ubuntu/CentOS/Amazon Linux,不久的将来也会支持 Windows,正式成为一门优秀的跨平台语言。


标准库更新


  • Float16 的支持,具有更好的运算性能

  • Apple Archive 一种功能类似 zip 的压缩文件,苹果就是用这种格式来更新系统

  • Swift System 对操作系统基础 API 的包装,让 API 更健壮易用

  • OSLog 推荐使用的 logging system


从这些更新可以看出,苹果对 Swift 的底层操作非常关心,Swift System 的出现让使用 Swift 底层开发者脱离 OS C API 的折磨,获得更一致更健壮的代码体验。


 新的一方库


  • Numerics 解决 Swift 中数学计算相关问题

  • ArgumentParser 为 Swift 编写脚本提供了强力的工具

  • StandardLibraryPreview 预览标准库中的新功能


 Code Size and Runtime


在使用 UIKit 的情况下,Swift 4.1 时生成的二进制代码已经从 OC 的两倍还多,但是在 Swift 5.3 中,这个差距已经缩小到小于 1.5 倍了。也就是说之前大量使用 Swift app 会自动得到二进制大小的优化,而对于担忧 Swift 会造成包大小问题的 App,现在已经不算是很大的问题了。因为只需要付出可以接受的代价,就能获得 Swift 带来的安全性能和开发体验。



如果 App 使用了纯 SwiftUI,二进制代码甚至可以缩小 43% 之多。可见苹果优化 Swift 的功底之深,而且这些优化,只需要从新编译一次即可享受,何乐而不为。



因为 Swift 更紧凑的值类型,运行时的内存,分配相同的对象所需的空间自然比 OC 更小。Swift 5.3 相较 5.1,运行时的必要额外信息存储要少非常多,甚至做到了比 OC 还要少,大大减小了 Swift 的运行时内存。这对低内存的设备是非常有帮助的,同时,更少的系统内存意味着更多的用户内存。而这一切,只需要重新编译即可。



Swift 底层的不断优化也让其成为一门高效的语言,降低运行时的要求,就可以提升其应用的场景。


 Swift Package Manager


SPM 作为 Swift 生态非常重要的一环,也迎来了更新。


  • SPM 支持二进制包分发

  • SPM 支持了资源的打包


这两点更新已经表明了 SPM 的能力已经足够完善了。目前具有一定规模 App 的内部模块都开始使用 Cocoapods 做二进制组件化的集成,这样可以明确对代码解耦,提高打包的效率。在这样的背景之下,SPM 对这两点关键特性的支持已经可以覆盖住大型 App 需求了,而且 SPM 不单单只跟 Swift 玩,C Family 它都可以支持。


在 SPM 与 Cocoapods 的对比中,亲儿子 SPM 跟 Xcode 深入整合,Xcode 可以直接打开编辑 swift package,Xcode 因为 SPM 设计了对应的操作界面,降低了开发和使用的门槛。成熟的工具链也让联调 Swift Package 轻而易举。而 Cocoapods 由社区维护,每一次 Xcode 更新其响应也不算很及时,在针对大型 App 时因为 Podfile 与 podspec 的分离导致了许多不一致,使用 ruby 还有一定的门槛。


现在也许是拥抱 SPM 的好时机。


 跨平台


现在官方支持的操作系统列表如下:


  • Apple platform

  • Ubuntu 16.04, 18.04, 20.04

  • CentOS 8

  • Amazon Linux 2

  • Windows (coming soon)


真正做到的跨平台,并且 Swift 官方支持 AWS Lambda。AWS Lambda Runtime 已经开源,支持了 AWS 的 FaaS 编程,进一步的拓宽了 Swift 涉足的领域。



调试能力(开发者体验)



调试和开发者体验也是一门语言非常重要的一环,因为没有人会写出没有错误的代码,检查错误的能力和工具对一门语言来说十分重要。苹果也十分注重这一方面,在开发者体验上下足了功夫。


 更加智能的诊断信息


刚开始使用 Swift 的开发者可能经常会对 Xcode 的报错信息不知所云,在引入 SwiftUI 后,这个问题尤为明显。笔者第一次编写 SwiftUI 时,只要 body 中某个地方出错,报出来的错误都是不正确的,只能通过肉眼检查和推断才能明白自己的错误,十分痛苦。


现在苹果重制了诊断能力,现在 Swift 的错误诊断比之前准确了许多,错误没有乱报并且错误提示也变得很好理解,特别是 SwiftUI,很容易知道错在哪了。在 Swift 中,编译通过就是对正确性的一个很好的证明,除非你用不安全的方式让编译器闭嘴。


 自动补全


经过强化的类型推断系统,也增强了 Swift 的代码补全能力。这个估计升级到 Xcode 12 就可以顺利体验了。同时代码缩进能力也得到了加强。


 LLDB




积极拥抱 Swift



看了这么多年 WWDC,每次看时大家应该都有一种心态


只支持最新版本,我们才支持 iOS X (低版本),这些东西跟我没关系

感觉 Swift 真香,但是现实只让我使用 OC(叹口气)

什么语言不是用,OC 这么多年肯定够用了


 危机


然而如果不及时做出改变,保持能用就行,在前进的路上,背上的担子就会越来越重。当发现快走不动时,又回过头来看 WWDC,就会发现,原来解决方案很久以前就已经给出来了,只是当时不觉得是个问题,这不支持那不合适,但是现在想拿出来使用的时候,面对背上那一团团的乱码,却又束手无策。


做出改变是痛苦的,但是当以前觉得痒就挠挠就解决了的事情,逐渐变成现在的痛点时,要做出改变也许会更痛苦。


Swift 的出现就是为了替代并且超越 Objective-C 的语言,虽然说苹果因为历史原因还在使用 OC,但是种种迹象表明,苹果正在做积极的工作,逐渐通过 Swift 降低 OC 在整个系统的比重。


社区也在积极的转变,许多著名的第三方库都已经迁移至 Swift,OC 版本已经不再维护,例如 Lottie 已经在 Swift 版本上出现了 OC 版本不存在的特性,并且 OC 版本不再维护。这种现象慢慢会越来越多。


 改变


我们也在积极探索 Swift 在手淘的落地,取得了 Swift 5.1 能模块在手淘中正确运行起来的阶段性成就。


现在时机已经成熟,语言特性,SPM,工具链,标准库都已经足够强大,是时候做出改变了。


Swift 虽然看起来很简单,但其实它是一种下限低,上限高的语言,集团内部的 Swift 环境,需要大家来一起维护。我们未来也要加强 Swift 语言相关的培训,让开发者真正理解 Swift,上手 Swift,成为一名 Swifter 而不是 OSwifter。


参考:


  1. SwiftUI 背后那些事儿

  2. WWDC20 What's new in Swift

  3. WWDC19 What's new in Swift

  4. WWDC18 What's new in Swift

  5. WWDC17 What's new in Swift

  6. WWDC16 What's new in Swift

  7. WWDC20 Swift packages: Resources and localization

  8. WWDC20 What's new in SwiftUI

  9. Swift 5 时代的机遇与挑战到底在哪里?

  10. Swift Evolution



手淘客户端团队

淘宝基础平台团队正在进行社招招聘,岗位有iOS Android客户端开发工程师、欢迎 转岗推荐。简历投递:junzhan.yzw@taobao.com


✿  拓展阅读

作者|蒋志远(星志)
编辑|橙子君
出品|阿里巴巴新零售淘系技术

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存