WWDC Quick Look 💓 By SwiftGGTeam
What’s new in Xcode 16

What’s new in Xcode 16

观看原视频

Highlight

这场 Session 覆盖了 Xcode 16 在开发全流程中的更新。编辑方面,代码补全用上了设备端训练的 Swift/Apple SDK 模型,能根据函数名和注释上下文给出更贴切的建议,这完全依赖 Apple Silicon 的本地算力。


核心内容

Xcode 16 的更新覆盖了编码、构建、调试、测试、性能分析五个阶段。先看一个痛点:Preview 里要用 @State,必须写一个只包含 @State 属性的包装视图,再在 Preview 里引用它。每个需要 Binding 的视图都要这么干,代码量翻倍,维护成本也随之上升。@Previewable 宏直接解决了这个问题——在 Preview 块里声明 @Previewable @State var currentFace = ...,预览系统在幕后生成包装视图,你只需要写两行代码。另一个痛点是多个 Preview 共享环境数据(比如 SwiftData 的 ModelContainer),每个 Preview 各自初始化一份,既重复又拖慢速度。PreviewModifier 协议让共享数据只初始化一次,由预览系统缓存。

构建方面,过去模块依赖扫描和模块编译是隐式嵌在源文件编译里的,构建日志只显示 “Compile xxx.swift”,出错时很难定位是模块问题还是源码问题。Explicit Modules 把编译拆成三个显式阶段:扫描依赖、构建模块、编译源码。每个阶段在构建日志和 Timeline 中独立可见,并行性更好,模块相关报错也清晰得多。C/Objective-C 默认开启,Swift 需要在 Build Settings 中手动 opt-in。

详细内容

Previewable 宏03:37)让 @State 等属性包装器直接在 Preview 块中使用:

#Preview {
    @Previewable @State var currentFace = RobotFace.heart

    RobotFaceSelectorView(currentFace: $currentFace)
}

关键点:

  • @Previewable 修饰 @State,预览系统在幕后创建包装视图,无需手写
  • currentFace 可以用 $currentFace 传 Binding,和正常 @State 行为一致
  • 只需两行代码即可 Preview 一个需要 Binding 的视图

PreviewModifier 协议04:40)解决预览间共享数据的问题:

struct SampleRobotNamer: PreviewModifier {
    typealias Context = RobotNamer

    static func makeSharedContext() async throws -> Context {
        let url = URL(fileURLWithPath: "/tmp/local_names.txt")
        return try await RobotNamer(url: url)
    }

    func body(content: Content, context: Context) -> some View {
        content.environment(context)
    }
}

关键点:

  • makeSharedContext()async throws,可以异步加载数据,且同类 Modifier 只调用一次,预览系统自动缓存
  • body(content:context:) 将共享数据注入视图层级,这里用 .environment() 注入
  • 配合 PreviewTrait 扩展可以把调用点压缩到 .sampleNamer 一个 trait

Swift Testing 框架13:42)替代部分 XCTest 用法:

import Testing
@testable import BOTanist

@Test
func plantingRoses() {
    let plant = Plant(type: .rose)
    let expected = Plant(type: .rose, style: .graft)

    #expect(plant == expected)
}

关键点:

  • @Test 宏标记测试函数,函数名随意取,不再受 test 前缀限制
  • #expect 接受任意布尔表达式,断言失败时自动输出值差异详情
  • 测试函数可用 .tags() 附加自定义 Tag,按 Tag 分组运行或从 Test Plan 中排除

Explicit Modules 构建06:26)将编译拆为扫描依赖、构建模块、编译源码三个阶段。构建日志中可见 “Scan dependencies”、“Compile Swift module” 等独立条目,Timeline 中也能看到各阶段的耗时分布。C/ObjC 默认开启;Swift 在 Build Settings 中开启 “Enable Explicitly Built Modules” 即可。另外,Xcode 16 还支持在 Swift Package 解析完成前就启动构建(07:15)。

调试改进:DWARF5 成为 macOS Sequoia / iOS 18 部署目标的默认调试符号格式,dSYM 更小、符号查找更快。Thread Performance Checker 新增慢启动和过量磁盘写入诊断。Unified Backtrace View(10:56)在 Debug Bar 开启后,可以连续滚动查看调用栈每一帧的代码和变量值,无需逐帧点击。RealityKit 调试器(12:16)可一键捕获空间应用的 Entity 层级快照,在 Xcode 内以 3D 视图浏览。

Instruments Flame Graph19:42)提供调用栈的面积可视化,左侧是最耗时的调用路径。Session 演示了用 Flame Graph 定位串行 asset.load() 循环,改为并行 Task Group 后启动时间显著缩短:

await withDiscardingTaskGroup { group in
    for asset in allAssets {
        group.addTask {
            asset.load()
        }
    }
}

核心启发

  • 做什么:在项目中逐步启用 Swift 6 Upcoming Features。为什么值得做:数据竞争从运行时偶现变成编译期必现,越早修成本越低。怎么开始:在 Build Settings 的 “Swift Compiler - Upcoming Features” 中逐个开启(如 Isolated Global Variables、Strict Concurrency),每次构建只面对一类警告,修完再开下一个。

  • 做什么:用 PreviewModifier 封装预览共享环境。为什么值得做:SwiftData ModelContainer、Mock 网络层等在多个 Preview 中重复初始化,既冗余又拖慢预览刷新。怎么开始:定义一个 PreviewModifier,在 makeSharedContext() 中初始化 ModelContainer 或 Mock 数据,扩展 PreviewTrait 添加 .myModifier trait,所有 Preview 用同一 trait 即可共享缓存数据。

  • 做什么:新测试文件用 Swift Testing 替代 XCTest。为什么值得做@Test 宏 + #expect 写法更简洁,参数化测试天然并行,Tag 机制比 XCTest 的 filter 更灵活。怎么开始:新测试文件 import Testing,用 @Test func xxx() 标记,#expect 做断言;已有 XCTest 不受影响,两者共存。

  • 做什么:为 Swift 目标开启 Explicit Modules。为什么值得做:编译拆为显式阶段后并行度更高、模块报错更清晰,lldb 表达式求值也能复用模块构建产物,调试更快。怎么开始:Build Settings 中开启 “Enable Explicitly Built Modules”,观察构建日志和 Timeline 中新增的 “Scan dependencies” / “Compile Swift module” 条目。

关联 Session

评论

GitHub Issues · utterances