WWDC Quick Look 💓 By SwiftGGTeam
Explore Packages and Projects with Xcode Playgrounds

Explore Packages and Projects with Xcode Playgrounds

观看原视频

Highlight

Xcode Playgrounds 一直是一个快速实验 Swift 代码的好工具,但过去它和实际项目之间有一道鸿沟——你不能直接在 Playground 中引用项目里的代码。Xcode 12 打通了这层隔阂。


核心内容

Playground 最适合做快速实验。开发者想试一个 API、验证一段 Swift 代码、写一份可运行教程时,不想先搭一个完整示例 App。问题在于,旧的 Xcode Playground 很容易停留在孤立草稿里:真实项目里的 framework、package dependency、asset catalog、Core ML 模型,都不一定能直接拿来跑。

Xcode 12 的变化来自现代构建系统。Playgrounds 接入同一套构建能力后,Xcode 知道怎样构建 Swift package、项目 target 和 playground 自己的 sources/resources,再把这些模块暴露给 playground 代码。session 先用 NutritionFacts package 展示可运行文档:文档写在 playground 里,示例代码可以执行,右侧还能显示 live view。

第二个场景更接近日常项目。Fruta 项目里有 NutritionFacts package dependency,也有一个 UtilityViews framework。SmoothieLab playground 打开后,Xcode 通过新的 Build Active Scheme 选项构建当前 scheme 里的 target,让 playground 能导入同一 workspace 里的 framework 和 package。这样,团队可以把 playground 放进项目,专门用来试验配方、图表或其他业务逻辑。

最后一段演示解决了资源问题。Xcode 12 的 playground 可以处理 asset catalog 和 ML model 这类需要构建步骤的资源。演讲者把 Fruta 的 ingredients asset catalog 拖进 playground resources,把 YOLOv3 模型也拖进去,Xcode 自动编译模型并生成 YOLOv3 Swift class。随后用 Vision 跑对象检测,再用 SwiftUI live view 看检测结果。

详细内容

Swift Package 文档可以直接运行

00:30)Xcode 12 把 Playgrounds 接入现代构建系统。这个集成让 Xcode 能构建 Swift packages,并把 package module 暴露给 playground 代码。NutritionFacts 的文档就放在 package 的 Playgrounds 文件夹里,用户打开 Package.swift 后,可以直接运行文档里的示例代码。

03:36)同一个 package 作为 Fruta 项目的依赖时,package 里的 playground 仍然可以打开和运行。(04:03)区别是依赖里的文件和其他 package 文件一样是只读的。这个限制很重要:它适合浏览和学习依赖的用法,不适合在依赖副本里直接改文档。

Build Active Scheme 让 playground 使用项目 target

04:35)SmoothieLab playground 打开时触发了构建。原因是 Xcode 12 增加了 Build Active Scheme 选项。开启后,Xcode 会自动构建当前 scheme 中的所有 target,并把这些 target 的 module 提供给同一 workspace 内的 playground。

这个设置直接影响项目里的工具型 playground。session 中的 SmoothieLab 用 UtilityViews framework 画营养图表,也能访问 NutritionFacts package。要让类似 playground 正常工作,需要确认两件事:目标 module 在 active scheme 里,或者它是 active scheme 构建 target 的依赖。

06:27)Xcode 12 还把 playground 的完整 build log 放进 Report navigator。构建失败时,你可以看到 active scheme 构建了哪些 target,playground 支持模块又编译了哪些 sources 和 resources。这对排查 “为什么这个 import 在 playground 里不可见” 很实用。

Playground resources 支持 asset catalog

08:42)演示从 Fruta 项目复制 ingredients asset catalog,并把它拖进 playground 的 resources 文件夹。Xcode 会编译 asset catalog,代码里再用标准 UIKit 入口加载图片。

import UIKit
let image = UIImage(named: "ingredient/orange")

关键点:

  • UIImage(named:) 使用 asset catalog 里的资源名,不需要手动解析文件路径。
  • "ingredient/orange" 对应 asset catalog 内的文件夹和图片名称。
  • 这段代码能运行,是因为 Xcode 12 先把 asset catalog 编译进 playground 支持模块。

Playground resources 支持 Core ML 模型

10:18)演讲者把 YOLOv3 模型拖进 playground resources。Xcode 自动编译模型,并根据模型生成 Swift class。playground 代码可以像项目代码一样实例化这个模型。

import CoreML
let yoloModel = try YOLOv3(configuration: MLModelConfiguration()).model

关键点:

  • import CoreML 引入 Core ML 框架。
  • YOLOv3 是模型编译后生成的 Swift class,名称来自模型详情里的 model class。
  • MLModelConfiguration() 使用默认模型配置。
  • .model 取出 Vision 后续要包装的 Core ML 模型对象。

用 Vision 把模型变成对象检测请求

10:54)有了模型和样例图片后,session 用 Vision 连接两者。VNCoreMLModel 包装 Core ML 模型,VNCoreMLRequest 负责对图片执行对象检测。

import UIKit
import CoreML
import Vision

let ingredientNames = [
    "banana",
    "orange",
    "almond-milk",
]

let yoloModel = try YOLOv3(configuration: MLModelConfiguration()).model
let model = try VNCoreMLModel(for: yoloModel)

let request = VNCoreMLRequest(model: model) {_,_ in }

关键点:

  • ingredientNames 限定本次 playground 要测试的三张样例图片。
  • VNCoreMLModel(for:) 把 Core ML 模型转成 Vision 可以执行的模型。
  • VNCoreMLRequest 创建一次可复用的 Vision 请求。
  • completion handler 在演示中先留空,结果稍后从 request.results 读取。

批量跑样例图片并整理识别结果

11:48)下一段代码遍历样例图片,用 VNImageRequestHandler 执行请求,再把 VNRecognizedObjectObservation 转成用于 SwiftUI 展示的数据结构。

let results = ingredientNames.compactMap { ingredient -> ObjectDetectionResult? in

    guard let image = UIImage(named: "ingredient/\(ingredient)") else { return nil }

    let handler = VNImageRequestHandler(cgImage: image.cgImage!)
    try? handler.perform([request])
    let observations = request.results as! [VNRecognizedObjectObservation]

    let detectedObjects = observations.enumerated().map { (index, observation) -> RecognizedObject in

        // Select only the label with the highest confidence.
        let topLabelObservation = observation.labels[0]
        let objectBounds = VNImageRectForNormalizedRect(observation.boundingBox, Int(image.size.width), Int(image.size.height))

        return RecognizedObject(id: index, label: topLabelObservation.identifier, confidence: Double(topLabelObservation.confidence), boundingBox: objectBounds)
    }

    return ObjectDetectionResult(name: ingredient, image: image, id: ingredient, objects: detectedObjects)
}

results

关键点:

  • compactMap 允许图片加载失败时返回 nil,成功的样例继续进入结果数组。
  • VNImageRequestHandler(cgImage:) 用当前图片创建 Vision 请求执行器。
  • handler.perform([request]) 对图片执行对象检测。
  • request.results 被转换为 [VNRecognizedObjectObservation],每个 observation 代表一个检测对象。
  • observation.labels[0] 取置信度最高的标签。
  • VNImageRectForNormalizedRect 把 Vision 的归一化 bounding box 转成图片坐标。

用 live view 直接看检测结果

12:33)最后,playground 把 SwiftUI visualizer 设置成 live view。右侧结果区会显示图片、红色 bounding box 和标签置信度。演示中,香蕉以 100% 置信度被识别,三颗橙子也被正确框出,杏仁奶被识别为 bottle。

import PlaygroundSupport

PlaygroundPage.current.setLiveView(
    RecognizedObjectVisualizer(withResults: results)
        .frame(width: 500, height: 800)
)

关键点:

  • PlaygroundSupport 提供 PlaygroundPage
  • setLiveView 把 SwiftUI view 放到 playground 的 live view 区域。
  • RecognizedObjectVisualizer(withResults:) 使用前一步整理出的检测结果。
  • .frame(width: 500, height: 800) 给可视化结果固定展示尺寸。

核心启发

  • 做什么:给 Swift package 增加一个 Playgrounds 文件夹,放入可运行教程。为什么值得做:Xcode 12 可以在 package 中运行 playground,读文档的人能马上执行示例代码并查看 live result。怎么开始:把最常用的 2-3 个 API 调用写成 playground 页面,确保示例只依赖 package 自身公开接口。

  • 做什么:在 App 项目里建立工具型 playground,用来调试业务规则或设计参数。为什么值得做:Build Active Scheme 可以把同一 workspace 的 framework 和 package dependency 暴露给 playground。怎么开始:新建 Playgrounds 文件夹,创建一个 playground,打开 inspector 确认 Build Active Scheme 开启,再导入项目内 framework。

  • 做什么:用 playground 快速验证 asset catalog 的资源命名和加载路径。为什么值得做:Xcode 12 会编译 playground resources,UIImage(named:) 可以直接验证 asset catalog 中的图片是否能按预期名称加载。怎么开始:把目标 asset catalog 拖进 playground resources,先写一行 UIImage(named:),再用 Quick Look 检查图片。

  • 做什么:为 Core ML 或 Vision 功能做一个离线样例 playground。为什么值得做:session 演示了把 .mlmodel、asset catalog、Vision 请求和 SwiftUI live view 放在同一个 playground 里验证模型效果。怎么开始:准备少量固定测试图片,拖入模型资源,使用 VNCoreMLRequest 跑检测,再用 live view 展示结果。

关联 Session

评论

GitHub Issues · utterances