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
- Build a SwiftUI view in Swift Playgrounds — 继续看如何在 Swift Playgrounds 中原型化 SwiftUI view,并保持与 Xcode 工作流兼容。
- Swift packages: Resources and localization — 深入理解 Swift package 如何携带图片、storyboard、localized strings 等资源。
- Distribute binary frameworks as Swift packages — 了解 Xcode 中 package dependency 与 framework 分发的另一条路径。
- Explore Computer Vision APIs — 扩展本场 YOLOv3 演示背后的 Vision、Core Image 和 Core ML 组合用法。
评论
GitHub Issues · utterances