What's new in Swift
Swift & UI 入门 30m

Swift 新特性一览

What's new in Swift

2020年6月22日

在 Apple 官方观看视频

一句话判断

Swift 5.3 不是一次小更新——multiple trailing closures、Package 资源支持、some 的扩展使用,每一个都在改变你写 Swift 的方式。

这场 Session 讲了什么

这是一场全景式的 Swift 新特性介绍,覆盖了 Swift 5.3(随 Xcode 12 发布)和 Swift 语言整体生态的进展。Session 按主题分组,从语法改进、包管理器增强、开发者工具体验到语言安全性等多个维度展示了 Swift 的最新状态。

语法层面最大的变化是 multiple trailing closures。以前如果函数有多个闭包参数,只有最后一个能用 trailing closure 语法,其余必须写成参数标签形式,导致代码可读性差。Swift 5.3 允许多个闭包都用 trailing closure 语法,配合清晰的标签名让代码结构一目了然。这对 SwiftUI 的 DSL 风格 API 尤其重要。

Package Manager 方面,Swift 5.3 终于支持了资源文件、本地化和二进制框架(binary targets)。这意味着 Swift Package 不再只是源码的容器,它现在可以包含图片、配置文件、甚至预编译的闭源 SDK。这是 SPM 赶上 CocoaPods 功能差距的决定性一步。

其他重要变化包括:some 关键字可以在更多上下文中使用(不只是返回值),增强了 opaque type 的灵活性;改进的错误诊断信息让编译器报错更容易理解;Swift 在 Linux 和 Windows 上的支持进一步完善。

值得深挖的点

Multiple Trailing Closures 对 SwiftUI 的影响

这个语法变化直接改变了 SwiftUI 的书写风格。以前 Button 的 action 和 label 只有一个能用 trailing closure:

// 旧语法(只有一个 trailing closure)
Button(action: { /* action */ }) {
    Text("Tap")
}

现在两个闭包都可以用 trailing closure:

// 新语法(多个 trailing closure)
Button {
    // action
} label: {
    Text("Tap")
}

这个改进让 SwiftUI 的声明式代码更接近自然语言的语序——先说做什么,再说看起来怎样。

Swift 生态的跨平台进展

Session 花了不少篇幅介绍 Swift 在 Apple 生态之外的进展。Swift 现在可以在 Ubuntu、CentOS、Amazon Linux 上运行,Windows 支持也在积极开发中。Swift Core Team 正在推动 Swift 成为系统编程语言的通用选择,而不仅仅是 Apple 平台的专属语言。

代码片段

// Multiple trailing closures 语法对比
// SwiftUI 视图修饰符的写法变化

// 旧写法:只能最后一个闭包用 trailing
UIViewRepresentable { context in
    // makeUIView
} updateHandler: { view, context in
    // updateUIView
}

// 新写法:所有闭包都用 trailing,带标签
UIViewRepresentable { context in
    // makeUIView
} update: { view, context in
    // updateUIView
}

// SwiftUI 中的实际效果
struct ContentView: View {
    var body: some View {
        List {
            ForEach(items) { item in
                Text(item.name)
            }
            .onDelete { indexSet in
                // 删除操作
                items.remove(atOffsets: indexSet)
            } onMove: { source, destination in
                // 移动操作
                items.move(fromOffsets: source, toOffset: destination)
            }
        }
    }
}
// enhanced opaque return type (some 的扩展使用)
protocol Container {
    associatedtype Item
    func getItem() -> Item
}

struct IntContainer: Container {
    func getItem() -> Int { 42 }
}

// some 现在可以在属性和变量声明中使用
struct ViewModel {
    // 属性也可以用 some
    var container: some Container {
        IntContainer()
    }
    
    // 在泛型约束中使用 some
    func process<T: Container>(_ container: some Container) -> some Container {
        return container
    }
}

// some 用于函数参数(反向泛型)
func makeView(data: some Codable) -> some View {
    Text("Loading...")
}
// Swift Package Manager 的资源支持
// Package.swift
// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "MyPackage",
    platforms: [.iOS(.v14), .macOS(.v11)],
    targets: [
        .target(
            name: "MyLibrary",
            resources: [
                .process("Resources"),  // 处理资源文件
                .copy("Config"),        // 原样复制
            ]
        ),
    ]
)

// 在代码中访问资源
let iconURL = Bundle.module.url(forResource: "icon", withExtension: "png")

最佳实践

  • 在 SwiftUI 代码中全面采用 multiple trailing closures 语法,旧语法虽然还能用,但新语法可读性更好
  • 利用 some 在属性声明中的支持,减少泛型参数的显式声明
  • 为 Swift Package 添加资源文件时,先规划好 resources 目录结构,与 Sources 目录平级
  • 关注 Swift Extensions 网站(swift.org),了解语言提案(SE-xxxx)的进展
  • 尝试在项目中使用 Swift Package 替代 CocoaPods 依赖,逐步迁移

还有什么值得关注

  • Swift 5.3 的编译速度相比 5.2 有约 20% 的提升,特别是增量编译场景
  • 新的 @main 属性让你可以标记程序的入口点,不再需要手动写 @UIApplicationMain
  • Session 预告了 Swift 并发(async/await)的方向——虽然正式发布要等到 Swift 5.5,但 5.3 已经为底层支持做了准备
  • Swift Driver(编译器驱动)被重写,大幅提升了 Xcode 中的构建性能
WWDC 2020