Highlight
WWDC25 では PhotoKit に新しい編集ノードチェーンとシーンフィルタ機能が導入され、サードパーティ App からシステムレベルのビジュアル解析結果を直接再利用できるようになりました。
主要内容
写真系 App における長年の悩みどころは「画像の選択」です。ユーザーのライブラリには数千枚もの写真が入っており、長大なスクロールリストを最後までめくらせるだけでも負担になります。そこに加えて App が「カバーに合いそうな写真」「料理が写っている写真」を選んでくれと求めれば、体験は悪化する一方です。これまで開発者がよく取っていた手法は、ピッカーで選択させた後にローカルで再度ビジュアル解析を走らせて、無関係な写真を除外してから後続フローに渡す、というものでした。代償として端末は発熱しバッテリーは減り、解析ロジックも自前でメンテし続ける必要がありました。
WWDC25 のこの session で示された解決策は、システムが既に計算済みの分類結果を開発者へ開放するというものです。システムは写真がライブラリに取り込まれた時点で、シーン認識・顔クラスタリング・テキスト認識といった解析を実行しています。これまでこの結果は「For You」「メモリー」などのシステム機能でしか使われていませんでしたが、PhotoKit はその入口をサードパーティ App にも開放しました。選択フェーズでは PHPicker に特定のシーンの写真だけを表示させることができ、編集フェーズでは新しいノードチェーンで「何をしたいか」を記述すれば、実行方法はシステムが決めてくれます。全体の思想は「計算」と「実行方法の決定」を切り離すことにあります。
詳細
PHPicker の API 形態自体は変わっておらず、開発者は引き続き PHPickerViewController でピッカーを呼び出します。違いは PHPickerConfiguration に新しい設定項目が増え、「特定のフィルタ条件に合致する写真だけを表示する」とシステムに伝えられるようになった点です。最も基本的な使い方は次のとおりです。
import PhotosUI
import SwiftUI
struct PhotoPickerExample: View {
@State private var selection: [PhotosPickerItem] = []
var body: some View {
PhotosPicker(
selection: $selection,
maxSelectionCount: 5,
matching: .images
) {
Label("写真を選択", systemImage: "photo.on.rectangle")
}
}
}
ポイント:
PhotosPickerは SwiftUI による PHPicker のラッパーで、selectionには選択結果を書き戻すための[PhotosPickerItem]配列をバインドします。maxSelectionCountで上限を指定します。指定しなければ単一選択になります。matching:はPHPickerFilterを受け取り、ピッカーに表示するコンテンツの種類を決めます。よく使うのは.images、.videos、.livePhotosです。新バージョンではこのフィルタにさらに細かい条件を重ねられるようになっており、たとえば特定のアルバムを情報源にしたり、スクリーンショットだけに限定したりできます。
写真ライブラリの読み書きは引き続き PHPhotoLibrary 経由です。権限のリクエストと変更通知の登録は別物として扱われており、新バージョンでは変更監視を Observable ベースの API へ移すことが推奨されています。これにより SwiftUI ビューがライブラリの変化を直接購読でき、PHPhotoLibraryChangeObserver を手書きするボイラープレートを避けられます。
import Photos
func requestLibraryAccess() async -> PHAuthorizationStatus {
await PHPhotoLibrary.requestAuthorization(for: .readWrite)
}
ポイント:
requestAuthorization(for:)はasync形式で権限状態を返すため、コールバックのネストを避けられます。.readWriteを渡すと読み書き両方の権限を要求します。読み取り専用のユースケースなら.addOnlyか.readWriteのうち必要十分なものを選び、用途に応じて使い分けてください。- 戻り値は
PHAuthorizationStatus列挙型です。.authorized、.limited、.deniedの 3 つの状態を意識して処理してください。limitedモードではユーザーが一部の写真だけを許可しているため、App は動作するもののアクセスできるリソースが少なくなります。
編集フローは PHAssetChangeRequest でリソースのメタデータを変更し、PHContentEditingOutput で編集結果を書き出します。新しいノードチェーンアーキテクチャはこれら 2 つの API の上に重ねられた記述レイヤーで、「まずクロップ、次にカラー調整、最後にフィルタ」といった線形のステップを、独立して調整可能なノード群として整理します。これにより「中間ステップを変更すると最初から計算し直しになる」問題を回避できます。
重要ポイント
-
何をするか: PhotoKit のシーンフィルタで自前の画像分類を置き換える
- なぜ価値があるか: システムが既に端末上で分類を計算済みなので、再利用するコストはゼロです。自分でモデルを走らせれば消費電力もメンテナンスコストもかかります。
- どう始めるか: App 内でシーンによるフィルタが必要な入口(「料理写真をアップロード」「壁紙にする風景写真を選ぶ」など)をすべて洗い出し、それらの入口のピッカー設定をシステムフィルタに切り替えていきます。
-
何をするか: ノードチェーンで複数ステップの画像編集を作り直す
- なぜ価値があるか: ユーザーは「途中の 1 ステップを取り消す」「特定のフィルタを無効化する」といった操作を当然のように期待します。従来の線形 output モデルではこのインタラクションを支えきれません。
- どう始めるか: まず最も複雑な編集パス(典型的には「クロップ + カラー調整 + フィルタ + ウォーターマーク」)を 1 つ選んでノードチェーンへ移行し、Undo の経路を検証します。その後、他のパスを段階的に追従させていきます。
-
何をするか:
PHPhotoLibraryChangeObserverを Observable ベースの API へ切り替える- なぜ価値があるか: 変更量は小さくリスクも低い一方、SwiftUI ビューが自然にライブラリの変化に反応できるようになり、App がバックグラウンドにあるときの無駄な再描画も減らせます。
- どう始めるか: コードベース内の
PHPhotoLibraryChangeObserver実装をすべて検索し、それらを@Observable型としてラップしてビュー層に公開し、段階的に置き換えていきます。
-
何をするか: ピッカー設定で「最低限必要」なフィルタ条件をハードコードしておく
- なぜ価値があるか: デフォルトのピッカーはライブラリ全体をユーザーにめくらせます。妥当な初期フィルタを加えれば、それだけでクリティカルパスを短縮できます。
- どう始めるか:
PhotosPickerを呼び出している箇所すべてについてmatching:引数をレビューし、ビジネス上の意味に沿って補強していきます。
関連 Session
- Enhancing your camera experience with capture controls — カメラ画面に物理ボタンとシステムレベルのキャプチャコントロールを組み込みます。
- Enhance your app with machine-learning-based video effects — 機械学習でビデオにフレームレート変換・超解像・ノイズ除去を加えます。
- Capture cinematic video in your app — Cinematic Video API でシネマティックなビデオを撮影します。
- Read documents using the Vision framework — Vision の新しい
RecognizeDocumentsRequestで構造化されたドキュメント認識を行います。 - What’s new in RealityKit — 写真素材を 3D シーンに取り込む新しいワークフローを紹介します。
コメント
GitHub Issues · utterances