WWDC Quick Look 💓 By SwiftGGTeam
What's new in Xcode 15

What's new in Xcode 15

观看原视频

Highlight

Xcode 15 通过更小的安装包(模拟器按需下载)、上下文感知的智能代码补全、资产目录 Swift 符号、String Catalog 本地化、实时文档预览、书签导航器、改进的源码控制提交编辑器、45% 更快的测试导航器、交互式 UI 测试回放、OSLog 结构化日志控制台、以及简化的 TestFlight 内部分发,让开发工作流从编码到分发全程更高效。

核心内容

更智能的代码补全

你在写 SwiftUI 时,给 VStack 加修饰符,Xcode 会建议 padding;给 Text 加修饰符,它会建议 font。Xcode 分析了你的代码上下文和常用模式后给出这些建议。

01:52

新建文件时,Xcode 会根据文件名建议类型名。函数调用时,按右方向键可以展开所有默认参数的排列组合,选择你需要的版本。已经用过的修饰符会被降权,避免重复建议。

03:28

资产目录的 Swift 符号

以前引用图片和颜色用字符串,拼写错误要到运行时才发现。Xcode 15 为资产目录中的每个资源自动生成 Swift 符号,代码中直接引用,重命名时构建报错,代码补全修正。

03:50

String Catalog 集中管理本地化

通过 Edit > Convert to String Catalog 把项目中的 .strings.stringsdict 文件迁移到统一的 String Catalog。所有翻译集中在一个编辑器中,左侧显示各语言进度,构建时自动检测新增和删除的字符串。

04:34

实时文档预览

写文档注释时,Editor > Assistant > Documentation Preview 提供实时预览。支持代码示例、截图引用,边写边看最终效果。

06:18

Swift Macros 集成

Xcode 15 完整支持宏的开发和调试。Quick Actions(Command-Shift-A)可以展开宏查看生成代码,在宏代码中设断点,逐步调试。新建宏包自带示例模板。

07:37

新 Preview API

#Preview 宏替代了原来的 PreviewProvider 协议。语法更简单,支持多个命名预览,支持 UIKit 和 AppKit 的 UIViewController/NSViewController 预览,widget 预览支持时间线导航。

08:50

书签导航器

Xcode 15 新增书签导航器,可以标记代码位置、Find 查询结果,支持分组和排序。书签可以作为待办列表,标记完成后可以删除。

10:13

改进的源码控制

新的变更导航器和提交编辑器,所有修改在一个滚动视图中查看。可以直接在提交编辑器中修改代码,变更即时反映。支持逐行 stage/unstage,文件可以同时包含已暂存和未暂存的修改。

12:30

测试改进

测试导航器用 Swift 重写,运行和报告速度提升 45%。测试报告提供 Insights 模式分析,识别可能相关的失败和耗时测试。UI 测试失败可以在交互式 Automation Explorer 中回放、检查 UI 层级。

15:07

OSLog 控制台

Xcode 15 控制台完整支持 OSLog,支持按子系统、类别、严重级别过滤。日志条目用背景色区分严重级别,元数据默认隐藏,点击展开。支持从日志条目跳转到生成它的代码行。

17:34

简化分发

Xcode Cloud 支持 TestFlight 测试说明随代码管理,支持 Mac 应用自动公证。Xcode 15 内置常用分发方式和推荐设置,TestFlight 内部测试构建只对团队可见。桌面通知提醒构建状态。

18:51

详细内容

上下文感知代码补全

struct PlantSummaryRow: View {
    var plant: Plant
    var body: some View {
        VStack {
            ComposedPlant(plant: plant)
                .padding(4)
                .padding(.bottom, -20)
                .clipShape(.circle)
                .background(.fill.tertiary, in: .circle)
                .padding(.horizontal, 10)

            VStack {
                Text(plant.speciesName)
            }
        }
    }
}

01:52

关键点:

  • 新建文件时,Xcode 根据文件名建议类型名(如 PlantSummaryRow.swift 建议 PlantSummaryRow
  • VStack 添加修饰符时,padding 排在前面,因为它是该视图最常用的修饰符
  • Text 添加修饰符时,font 排在前面
  • 已经用过的修饰符(如已经加了 font)会被降权,避免重复建议
  • 成对属性智能关联:输入 latitude 后,下一个建议会是 longitude

函数默认参数展开

// 按右方向键展开所有参数组合
.frame(/* 展开后显示多个选项 */)
// .frame(width:)
// .frame(height:)
// .frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)

02:32

关键点:

  • 函数调用时按右方向键展开所有默认参数的排列组合
  • 选择需要的版本,避免手动删除不需要的参数
  • 特别适用于 SwiftUI 修饰符,如 framepadding

资产目录 Swift 符号

// 以前:字符串引用,无类型安全
Image("MyCustomImage")

// Xcode 15:Swift 符号引用
Image(.myCustomImage) // 代码补全可用,重命名时构建报错

03:50

关键点:

  • 颜色和图片资产自动生成 Swift 符号
  • 代码中直接引用,享受代码补全和类型检查
  • 重命名资产后,构建时报错,通过代码补全快速修正
  • 彻底消除运行时”图片找不到”的问题

String Catalog 迁移

// 迁移前:分散的 .strings 文件
// Localizable.strings
// "welcome_title" = "Welcome";

// 迁移后:String Catalog 集中管理
// 构建时自动从源代码提取字符串
// 左侧边栏显示各语言翻译进度
// 新增/删除的字符串自动标注

04:34

关键点:

  • Edit > Convert to String Catalog 启动迁移
  • 自动收集所有 storyboard、.strings、.stringsdict 文件
  • 构建时自动从源代码提取字符串,保持同步
  • 新增字符串用徽章标记,翻译进度一目了然

文档注释与实时预览

/// Create the bird icon view.
///
/// The bird icon view is a tailored version of the ``ComposedBird`` view.
///
/// Use this initializer to display an image of a given bird.
///
/// ```swift
/// var bird: Bird
///
/// var body: some View {
///     HStack {
///         BirdIcon(bird: bird)
///             .frame(width: 60, height: 60)
///         Text(bird.speciesName)
///     }
/// }
/// ```
///
/// ![A screenshot of a view containing a bird icon with the bird's species name below it.](birdIcon)

06:18

关键点:

  • 使用 Markdown 语法编写文档注释
  • ComposedBird 创建符号链接到相关类型
  • ![描述](imageName) 引用文档 catalog 中的图片
  • Editor > Assistant > Documentation Preview 实时查看效果

Swift Macros 在 Xcode 中的使用

// CaseDetection 宏:自动生成枚举的 isXxx 属性
@CaseDetection
enum Element {
    case one
    case two
}

var element: Element = .one
if element.isOne {
    // Handle interesting case
}

08:07

// 宏实现示例
public struct CaseDetectionMacro: MemberMacro {
    public static func expansion<
        Declaration: DeclGroupSyntax, Context: MacroExpansionContext
    >(
        of node: AttributeSyntax,
        providingMembersOf declaration: Declaration,
        in context: Context
    ) throws -> [DeclSyntax] {
        declaration.memberBlock.members
            .compactMap { $0.decl.as(EnumCaseDeclSyntax.self) }
            .map { $0.elements.first!.identifier }
            .map { ($0, $0.initialUppercased) }
            .map { original, uppercased in
                """
                var is\(raw: uppercased): Bool {
                    if case .\(raw: original) = self {
                        return true
                    }
                    return false
                }
                """
            }
    }
}

07:37

关键点:

  • Quick Actions(Command-Shift-A)展开宏查看生成代码
  • 可以在宏生成的代码中设断点调试
  • 新建宏包自带模板和示例
  • 宏生成的是普通 Swift 代码,可以像手写代码一样调试

新 Preview API

// SwiftUI 预览
#Preview {
    AppDetailColumn(screen: .account)
        .backyardBirdsDataContainer()
}

#Preview("Placeholder View") {
    AppDetailColumn()
        .backyardBirdsDataContainer()
}

// UIKit 预览
#Preview {
    let controller = DetailedMapViewController()
    controller.mapView.camera = MKMapCamera(
        lookingAtCenter: CLLocation(latitude: 37.335_690, longitude: -122.013_330).coordinate,
        fromDistance: 0,
        pitch: 0,
        heading: 0
    )
    return controller
}

08:50

关键点:

  • #Preview 宏替代 PreviewProvider 协议
  • 支持命名预览,方便区分不同场景
  • 支持 UIKit 和 AppKit 的 ViewController 预览
  • Widget 预览支持时间线导航,查看不同时间点的状态

OSLog 结构化日志

import OSLog

let logger = Logger(subsystem: "BackyardBirdsData", category: "Account")

func login(password: String) -> Error? {
    var error: Error? = nil
    logger.info("Logging in user '\(username)'...")

    // ...

    if let error {
        logger.error("User '\(username)' failed to log in. Error: \(error)")
    } else {
        loggedIn = true
        logger.notice("User '\(username)' logged in successfully.")
    }
    return error
}

17:34

关键点:

  • Logger 按子系统和类别组织日志
  • 支持 .debug.info.notice.error 等级别
  • Xcode 控制台用背景色区分严重级别
  • 支持按子系统、类别、级别过滤
  • 点击日志条目可跳转到生成它的代码行

核心启发

1. 迁移资产目录到 Swift 符号引用

搜索项目中所有 Image("string")Color("string") 的用法,替换为符号引用。这消除了运行时资源缺失的风险,同时享受代码补全。入口是构建项目,Xcode 15 会自动生成符号,然后逐个替换字符串引用。

2. 用 String Catalog 替换分散的本地化文件

通过 Edit > Convert to String Catalog 把项目迁移到统一的本地化管理系统。后续新增字符串会自动提取,翻译进度一目了然。入口是 Xcode 菜单 Edit > Convert to String Catalog。

3. 用 #Preview 替换所有 PreviewProvider

新项目直接用 #Preview 宏,旧项目逐步替换。代码更简洁,支持更多预览场景(UIKit、AppKit、Widget 时间线)。入口是把 struct Xxx_Previews: PreviewProvider 改成 #Preview { ... }

4. 用 OSLog 替换 print 和 NSLog

在项目中引入 import OSLog,用 Logger 替代 printNSLog。结构化日志支持过滤、跳转、严重级别区分,调试效率大幅提升。入口是定义模块级别的 Logger 常量,逐步替换日志调用。

5. 用书签导航器管理开发任务

在开发过程中,用右键 > Bookmark 标记需要回头处理的位置。可以标记代码行、Find 查询结果,支持分组和完成标记。入口是右键点击代码行或 Find 结果,选择 Bookmark。

关联 Session

评论

GitHub Issues · utterances