Highlight
Swift 5.3 把更新集中在运行时体积和内存、Xcode 诊断和补全、跨平台支持、
@main与多尾随闭包、Apple Archive、OSLog、Swift Numerics 和 ArgumentParser,让 Swift 能覆盖 app、命令行工具、系统层库和服务器函数。
核心内容
Swift 5 已经完成 ABI stability 和 API stability,SwiftUI 也把 Swift 推到了 Apple 平台开发的中心。到了 WWDC20,问题变成了另一个层面:Swift 是否足够轻、足够好调试、足够适合系统层和服务器场景(00:14)。
这场 session 的回答先从底层性能开始。Swift 5.3 继续缩小代码体积差距,Swift 版本的 UIKit app 已经降到 Objective-C 版本代码体积的 1.5 倍以下;MovieSwiftUI 的应用逻辑代码体积减少超过 40%。堆内存也同步下降,同一个 Swift app 在新版本里的启动期 runtime overhead 降到上一年版本的三分之一以下(02:29、06:04)。
开发体验也被放在同等重要的位置。编译器诊断开始指向更精确的位置,并给出更多 fix-it 线索;SourceKit 驱动的补全和缩进针对 SwiftUI 链式调用做了优化,部分补全场景相比 Xcode 11.5 快到 15 倍;LLDB 在 Clang module 导入失败时可以从 DWARF debug information 回退导入 C 和 Objective-C 类型,让变量视图和表达式求值更可靠(07:18、09:31、10:58)。
语言层面,Swift 5.2 和 5.3 增加了十多个特性。Session 挑出几个会直接改变日常代码形态的点:多尾随闭包让带多个 closure 参数的调用更适合 DSL;@main 把入口点从特殊的 main.swift 扩展成类型协议能力;KeyPath expression 可以当函数传递;enum 可以自动合成 Comparable,也可以用 enum case 满足 static protocol requirement(15:02、20:09、23:29)。
最后一部分把 Swift 从语言更新推向生态更新。SDK 里出现 Float16、Apple Archive、Swift System 和更快的 OSLog;Swift Package Manager 之外还有 Swift Numerics、Swift Argument Parser 和 Swift Standard Library Preview。它们共同指向一个变化:Swift 的新能力不只等系统 SDK 发布,也会先通过开源 package 进入开发者手里(26:04、28:54、30:38)。
详细内容
运行时优化让 Swift 更适合系统层
(02:29)Swift 5.3 的优化来自 runtime 和工具链层面的累积,并不对应单个 API。Session 给出两个具体指标:一个 Swift UIKit app 的代码体积已低于 Objective-C 版本的 1.5 倍;MovieSwiftUI 的应用逻辑代码体积减少超过 40%。这会影响下载体积,也会影响可被系统回收的 clean memory。
(05:15)堆内存示例说明了 Swift value type 的收益:400 个模型对象在 Swift 里约占 20KB heap memory,Objective-C 版本约占 35KB。Swift 5.3 还降低了启动期 caches、protocol conformance、type information 和 Objective-C bridging 相关开销,让一个 Swift app 的 heap memory 低于上一年版本的三分之一。
(06:52)Standard Library 被放到 Foundation 下方后,Swift 可以用于实现低于 Objective-C 层级的框架。这个改动解释了为什么 Apple 要持续压 runtime memory:系统 daemon 和低层框架对每一字节都敏感。
关键点:
- 代码体积优化、clean memory 和 heap memory 是这场 session 的开场主线,不是附带指标。
- value type、small string、连续数组存储解释了 Swift 模型数据更紧凑的原因。
- Standard Library 位置下沉意味着 Swift 能进入过去更多依赖 C 的系统层场景。
跨平台 Swift 和 AWS Lambda
(12:34)Swift 5.3 更新了 Ubuntu 支持,增加 CentOS 和 Amazon Linux 2,并预告 Windows 初始支持。Session 随后把跨平台能力落到 AWS Lambda:用开源 Swift AWS runtime 写 serverless function。
import AWSLambdaRuntime
Lambda.run { (_, event: String, callback) in
callback(.success("Hello, \(event)"))
}
关键点:
import AWSLambdaRuntime说明这项能力来自开源 runtime package,而非 Foundation 或系统 SDK API。Lambda.run注册 Lambda handler,闭包接收事件并通过 callback 返回结果。event: String展示了演示里最小的输入模型,适合说明 Swift 在服务器函数里的启动方式。callback(.success(...))把返回值交给 Lambda runtime,示例刻意保持到 “Hello, world” 级别。
@main 把入口点交给类型
(20:09)过去 AppDelegate 可以用 UIApplicationMain 让编译器生成隐式 main.swift。Swift 5.3 把这种能力泛化为 @main:库作者在协议或父类上定义 static main,使用者把入口类型标注为 @main,编译器生成入口代码。
// Type-based program entry points
import ArgumentParser
@main
struct Hello: ParsableCommand {
@Argument(help: "The name to greet.")
var name: String
func run() {
print("Hello, \(name)!")
}
}
关键点:
import ArgumentParser引入的是 Swift open-source package,后文的 Argument Parser 示例会继续扩展它。@main标在Hello类型上,入口点从单独文件变成类型声明的一部分。ParsableCommand提供命令行工具约定,库作者可以通过协议把入口规则暴露给用户。@Argument把命令行位置参数声明为属性,run()是真正执行命令逻辑的地方。
enum 自动合成 Comparable
(23:29)Swift 4.1 已经能合成 Equatable 和 Hashable。Swift 5.3 继续扩展到符合条件的 enum Comparable,让有自然顺序的状态枚举少写样板代码。
// Synthesized comparable conformance for enums
enum MessageStatus: Hashable, Comparable {
case draft
case saved
case failedToSend
case sent
case delivered
case read
var wasSent: Bool {
self >= .sent
}
}
关键点:
MessageStatus同时声明Hashable和Comparable,比较逻辑由 compiler synthesize。- case 的声明顺序就是比较顺序,
.sent之后的状态都代表已经发出。 wasSent用self >= .sent表达业务规则,比手写 switch 更短。- 这个例子适合状态机、消息队列、同步阶段等有线性顺序的 enum。
Apple Archive 和 Swift System
(26:55)Apple Archive 是新的模块化归档格式,基于 Apple 用来交付系统更新的技术,提供 Finder 集成、命令行工具和 Swift API。示例展示了把目录写入 .aar 文件,并用 LZFSE 压缩。
// Apple Archive
import AppleArchive
try ArchiveByteStream.withFileStream(
path: "/tmp/VacationPhotos.aar",
mode: .writeOnly,
options: [.create, .truncate],
permissions: [.ownerReadWrite, .groupRead, .otherRead]
) { file in
// Receives raw bytes and writes compressed bytes to `file`
try ArchiveByteStream.withCompressionStream(using: .lzfse, writingTo: file) { compressor in
// Receives archive entries, and writes bytes to `compressor`
try ArchiveStream.withEncodeStream(writingTo: compressor) { encoder in
// Writes all entries from `src` to `encoder`
try encoder.writeDirectoryContents(archiveFrom: source, keySet: fieldKeySet)
}
}
}
关键点:
ArchiveByteStream.withFileStream创建目标文件流,options和permissions使用强类型枚举。withCompressionStream(using: .lzfse, writingTo: file)把原始字节压缩后写到文件。ArchiveStream.withEncodeStream接收 archive entries,再交给压缩流。writeDirectoryContents(archiveFrom:keySet:)负责把源目录写入 archive,示例里的source和fieldKeySet来自演示上下文。- Session 特别指出 FileStream 构造器依赖 Swift System,它用强类型包装低层系统调用,减少 Darwin overlay 原始接口的易错点。
OSLog 的字符串插值和格式化
(28:11)OSLog 的目标是低开销和隐私保护。Swift 5.3 通过 compiler optimization 加速 OSLog,并增加字符串插值与格式化选项,让日志写法更接近普通 Swift 字符串。
logger.log("\(offerID, align: .left(columns: 10), privacy: .public)")
// Logs "E1Z3F "
logger.log("\(seconds, format: .fixed(precision: 2)) seconds")
// Logs "1.30 seconds"
关键点:
privacy: .public明确把offerID标为可公开显示,符合 unified logging 默认保护敏感数据的设计。align: .left(columns: 10)让字段在日志里按列对齐,便于后续查看。format: .fixed(precision: 2)让数值保留两位小数,避免手动字符串格式化。- 如果项目还在用
print调试线上问题,这组 API 是迁移到统一日志的入口。
ArgumentParser 让命令行工具保持声明式
(29:48)Swift Argument Parser 是新的开源 package。Session 用同一个 Hello 命令继续演示:添加 count option 后,工具能重复输出 greeting,并自动获得参数校验和帮助信息。
// Swift ArgumentParser
import ArgumentParser
@main
struct Hello: ParsableCommand {
@Option(name: .shortAndLong, help: "The number of times to say hello.")
var count: Int = 1
@Argument(help: "The name to greet.")
var name: String
func run() {
for _ in 1...count {
print("Hello, \(name)!")
}
}
}
关键点:
@Option(name: .shortAndLong)让count同时支持短参数和长参数形式。var count: Int = 1同时声明类型和默认值,Argument Parser 会据此做解析和校验。@Argument继续表示位置参数,help文案进入自动生成的帮助页。run()里只保留业务逻辑,入口、参数解析、帮助屏幕都交给 package 处理。
核心启发
-
做什么:给现有 Swift app 做一次体积和堆内存回归检查。为什么值得做:Swift 5.3 的代码体积、SwiftUI app 逻辑体积和 runtime heap overhead 都有明确优化,老项目升级后可能直接受益。怎么开始:用同一份代码分别在旧 Xcode 和 Xcode 12 上 Archive,对比 binary size;在 Instruments 里记录启动后的 heap memory。
-
做什么:把内部脚本改成 Swift Argument Parser 命令行工具。为什么值得做:
@main和ParsableCommand能把入口、参数声明和帮助信息放在一个类型里,减少手写main.swift和参数解析代码。怎么开始:新建 Swift Package,引入apple/swift-argument-parser,把脚本参数拆成@Option和@Argument。 -
做什么:为线上诊断日志建立 OSLog 包装层。为什么值得做:Swift 5.3 的 OSLog 支持字符串插值、隐私标记和格式化,能替代散落的
print,也能降低泄露敏感信息的风险。怎么开始:从一条关键业务链路开始,定义Logger分类,把用户输入默认保持 private,只把必要 ID 标成.public。 -
做什么:把资源型组件拆成 Swift Package。为什么值得做:本场提到 Swift Package 生态扩展,相关 session 10169 继续讲资源和本地化;组件包可以同时带代码、图片、storyboard 和 localized strings。怎么开始:先抽一个设计系统或空状态组件包,按
Sources、Resources和.process组织文件,再在 app target 中替换本地引用。 -
做什么:用 Apple Archive 做开发资产打包工具。为什么值得做:Apple Archive 提供 Swift API、LZFSE 压缩和命令行工具,适合把示例数据、日志包或设计资源归档成可传输文件。怎么开始:把 session 的
withFileStream、withCompressionStream、withEncodeStream示例改成一个内部 CLI,输入目录,输出.aar。
关联 Session
- Distribute binary frameworks as Swift packages — 用 Swift Package 分发 XCFramework,配置 binary target,并用 checksum 保证客户端拿到预期二进制。
- Explore logging in Swift — 深入 Swift unified logging API,理解隐私保护、字符串插值、格式化和低开销日志采集。
- Explore numerical computing in Swift — 介绍 Swift Numerics、Float16、泛型数值协议和复数类型,补充本场提到的数值计算生态。
- Swift packages: Resources and localization — 讲解 Swift Package 中的资源文件、图片、storyboard 和本地化字符串组织方式。
- What’s new in SwiftUI — 展示 SwiftUI 在 2020 年的新 app、scene、widget、outline、grid 和 toolbar 能力。
评论
GitHub Issues · utterances