Photos 新特性
What's new in Photos
2025年6月11日
一句话判断
Apple 终于把照片库的”理解能力”交给了第三方——PhotoAnalysis API 是今年 Photos 框架里真正改变游戏规则的东西,PHPicker 智能筛选和编辑管线反而是锦上添花。
这场 Session 讲了什么
你有没有遇到过这种场景:用户在你的 App 里选照片,面对几千张缩略图无从下手,最后随便选了几张了事?PHPicker 今年加了 sceneFilter,你可以直接告诉选择器”我只要风景照”或者”我只要食物照”,系统会在设备端用预计算的场景标签帮你过滤。不是实时分析——照片导入时标签就打好了,所以筛选几乎是瞬间完成的。
另一个大变化是编辑架构的重构。以前用 PHContentEditingOutput 做照片编辑,操作是线性叠加的,想改中间一步得从头来。新的 PHAssetEditRequest 把编辑组织成节点链(node chain),每个节点可以独立调整、禁用甚至删除,其他节点完全不受影响。而且这套架构是”描述性”的——你告诉系统”我要做什么”,系统自己决定怎么执行最优,包括 GPU 加速和异步处理。
但真正让人心动的是 PhotoAnalysis。它把 Apple 设备端的视觉理解能力开放给了第三方应用:场景分类、物体识别、OCR 文本提取,全部在 Neural Engine 上跑,照片不离开设备。以前你要做”自动按主题整理相册”这种功能,要么自己训练模型,要么调云端 API 现在一个 API 调用就搞定了。
值得深挖的点
PhotoAnalysis 的真正含义:第三方应用第一次”看见”照片
表面上看,PhotoAnalysis 就是一个图像分类 API。但如果你仔细想想,这在 Apple 生态里是破天荒的。过去十年,Apple 的视觉智能能力(Visual Intelligence)只给自家的照片 App 用——你打开相册,它能识别出”海滩""狗""你的朋友”,但第三方开发者碰不到这个能力。现在它公开了。
这个 API 的设计选择很有意思。它不是给你一个低级的 Core ML 模型让你自己推理,而是直接给你语义化的结果——“这张照片 87% 是海滩场景”,“左上角识别出一行文字’OPEN 24H’“。这意味着 Apple 刻意选择了”高层抽象”而非”底层灵活”的路线。好处是开发者不需要处理模型选择、预处理、后处理这些脏活;代价是你没法微调模型,也没法拿到原始的特征向量。
另一个值得注意的细节是置信度阈值。API 返回的每个分类结果都带 confidence 值,但文档没有建议具体阈值。实际使用中,0.7 以上通常比较可靠,低于 0.5 基本是噪声。你需要自己根据场景调——做自动分类相册可以用高阈值保证准确率,做搜索建议可以适当降低以提高召回率。
编辑管线的 trade-off:灵活性 vs 性能
PHAssetEditRequest 的节点图设计在概念上很优雅,但有一个容易被忽略的问题:非破坏性意味着每次渲染最终图片时,系统需要从原始数据开始,按顺序执行所有节点。五个节点可能没什么感觉,但如果你的 App 允许用户叠加 20 个编辑操作,预览时的计算量就不可忽视了。
Apple 的解决方案是把执行策略交给系统——它会在后台预渲染、用 GPU 加速、缓存中间结果。但这也意味着你放弃了对执行过程的控制。旧的 PHContentEditingOutput 虽然笨重,但你明确知道每一步在做什么。新架构下,你描述意图,系统执行——这是一种”信任系统”的模式。
对大多数 App 来说,这是一笔划算的交易。但如果你在做专业级修图工具,需要对编辑管线有精确控制(比如实时预览每一帧的中间状态),你可能还是需要在 PHAssetEditRequest 之上再包一层自己的渲染管线。
代码片段
// 场景:旅行 App 让用户快速选择风景和美食照片
import PhotosUI
var config = PHPickerConfiguration()
config.selectionLimit = 10
config.filter = .images
// 新增:按场景类型过滤,照片导入时已预计算标签,筛选是即时的
config.sceneFilter = PHPickerSceneFilter(including: [.landscape, .food])
let picker = PHPickerViewController(configuration: config)
// 坑:sceneFilter 是"建议"不是"强制",用户仍可通过搜索找到所有照片
// 场景:相册 App 自动按主题给照片分组
import Photos
let request = PhotoAnalysisRequest(asset: asset)
request.options = [.sceneClassification, .objectDetection, .textRecognition]
let result = try await PhotoAnalysis.perform(request)
for scene in result.sceneClassifications ?? [] {
print("\(scene.label): \(scene.confidence)") // confidence 0-1,建议 > 0.7 时认为可靠
}
// 坑:批量分析几千张照片时务必放到后台队列,否则主线程会被卡死
// 场景:修图 App 让用户叠加编辑并可独立撤销任何一步
import Photos
let editRequest = PHAssetEditRequest(asset: asset)
editRequest.pipeline = [
EditNode.brightness(0.3),
EditNode.contrast(1.2),
EditNode.saturation(0.9),
]
try await editRequest.commit()
// 只改亮度,其他节点不受影响
editRequest.pipeline[0] = EditNode.brightness(0.5)
try await editRequest.commit()
// 坑:pipeline 的顺序影响最终效果——先裁剪再调色 vs 先调色再裁剪结果不同
最佳实践
优先做 PhotoAnalysis 的集成,而不是 PHPicker 的智能筛选。原因很简单:PhotoAnalysis 能力最稀缺,市场上没有等价的替代品;而 PHPicker 的 sceneFilter 加不加,用户选照片的体验差别没那么大——他们习惯了滚动浏览。
具体路径:先用 PhotoAnalysis 做一个”智能相册”功能,把用户的照片自动按场景分组。这个功能开发成本低(API 很简洁),但用户感知强烈。等这个功能稳定了,再考虑用 sceneFilter 优化选择器的入口体验。
编辑管线的迁移放在最后。PHContentEditingOutput 没有被废弃,简单的滤镜场景下旧方案完全够用。只有当 App 需要”多步编辑 + 独立撤销”这种复杂交互时,才值得投入迁移成本。
另外,不管先做哪个功能,第一时间把 PHPhotoLibraryChangeObserver 换成 PHPhotoLibraryChangeObservation。这个改动最小、风险最低,但能立刻减少 App 在后台时的无效 UI 刷新。
还有什么值得关注
- PHPicker 主题自定义:选择器现在支持自定义外观,终于能和你的 App 视觉风格保持一致了,不用再忍受那个突兀的系统默认样式。
- 细粒度变更观察:
PHPhotoLibraryChangeObservation可以按特定相册或资产类型监听变更,替换掉旧的全量观察者能显著降低后台资源消耗。 - 编辑管线的 GPU 加速:系统会自动利用 GPU 处理编辑节点,开发者不需要写任何 Metal 代码就能获得性能提升。