WWDC Quick Look 💓 By SwiftGGTeam
Discover PhotoKit change history

Discover PhotoKit change history

元の動画を見る

ハイライト

以前は、写真ライブラリの変更を追跡するのは非常に面倒でした。新しいアセットは日付でクエリする必要があり、変更は変更日と比較する必要があり (ただし、正確ではありません)、削除には完全な差分が必要です。 3 つの操作には 3 つの異なる検出方法が必要ですが、パフォーマンスのオーバーヘッドが高く、結果の信頼性が低くなります。


主要内容

写真アプリの一般的な要件は、そのインターフェイスをシステムの写真ライブラリと同期することです。

Session の例は登山ソーシャル アプリです。ユーザーがハイキング ワークアウトを完了すると、アプリはエクササイズの開始時間と終了時間に基づいて写真ライブラリから関連する写真を選択し、コラージュを生成します。後で友人が新しいハイキング写真を送った場合、またはユーザーが写真を編集した場合、コラージュは更新されるはずです。 (00:54)

古い方法には 3 つのステップが含まれます。

新しい写真を追加するには、creationDateクエリ。写真を変更するには、追跡されたアセットを再取得して再度確認してくださいmodificationDate。写真の削除が一番面倒です。追跡されたすべてのアセットを取得してから、ローカル レコードとの差分を実行する必要があります。 Appleは特に次のように述べていますmodificationDateまた、写真ライブラリ内の内部処理アクティビティによって変更され、誤検知が発生する可能性もあります。 (01:25)

PhotoKit には永続的な変更履歴が導入されています。挿入、更新、削除など、写真ライブラリの変更をタイムラインに記録します。アプリは永続的な変更トークンを保存し、次回起動時にこのトークンを使用して後続の変更をクエリします。 (02:42)

このトークンは、特定の時点での写真ライブラリのステータスを表し、アプリ間で保存できます。これはデバイスのローカル トークンであり、アクセス コストが低くなります。アプリが制限付きライブラリ モードの場合、ユーザーが許可した PhotoKit オブジェクトの変更のみが返されます。 (03:17)

永続的な履歴はオフラインでの変更を補完します。オリジナルPHChangeこれは、アプリの実行中にメモリ内のフェッチ結果をリアルタイムで変更するのに適しています。永続的な履歴は、アプリが非アクティブなときに写真ライブラリの変更を追跡するために使用されます。必要に応じて 2 つを組み合わせることができます。 (05:10)


詳細

従来の慣例: 3 種類の変更には 3 セットの検査が必要

(01:25) 新しいアセットの追加は簡単そうに思えます。最後の起動時間を記録してクエリを実行します。creationDate写真より後です。

// Discover added assets
let options = PHFetchOptions()
options.predicate = NSPredicate(format: "creationDate > %@", lastLaunchDate as CVarArg)
let insertedAssets = PHAsset.fetchAssets(with: options)

キーポイント:

  • PHFetchOptions()PhotoKit クエリ構成を作成します。 -predicate結果を前回の起動以降に作成されたアセットに限定します。 -PHAsset.fetchAssets(with:)可能な新しい写真アセットを返します。

(01:46) 変更と削除には、アプリによって記録されたアセットを再確認する必要があります。

let fetchResult = PHAsset.fetchAssets(with: localIdentifiers, options: nil)
// Discover all modified and deleted assets
fetchResult.enumerateObjects { asset, idx, stop in
    if asset.modificationDate?.compare(lastLaunchDate) == .orderedDescending {
        // Asset could have been modified
    }
    if !localIdentifiers.contains(asset.localIdentifier) {
        // Asset could have been deleted
    }
}

キーポイント:

  • localIdentifiersアプリが追跡した写真のローカル識別子です。 -fetchAssets(with:options:)これらのアセットを写真ライブラリから取得します。 -modificationDate前回の起動時よりも遅い場合は、システムの内部処理によってこの日付も更新される可能性があるため、資産が変更された可能性があることを意味するだけです。 -localIdentifierアセットがローカル レコードにない場合にのみ、アプリはアセットが削除された可能性があると推測できます。

このコードは古いソリューションのコストを反映しています。追加、変更、削除にはそれぞれ独自のロジックがありますが、結果はまだ不確かです。

新しいアプローチ: トークンを使用して永続的な変更をプルします

(04:33) 新しい入り口はPHPhotoLibrary.fetchPersistentChanges(since:)。アプリは最後に保存されたトークンを渡し、PhotoKit はトークンの後の永続的な変更を返します。

let persistentChanges = try! PHPhotoLibrary.shared().fetchPersistentChanges(since: self.lastStoredToken)

for persistentChange in persistentChanges {
   if let changeDetails = persistentChange.changeDetails(for: PHObjectType.asset) {
        let updatedIdentifiers = changeDetails.updatedLocalIdentifiers
        let deletedIdentifiers = changeDetails.deletedLocalIdentifiers
        let insertedIdentifiers = changeDetails.insertedLocalIdentifiers
    }
}

// After processing change details
self.lastStoredToken = lastPersistentChange.changeToken

キーポイント:

  • lastStoredTokenこれは、最後の写真ライブラリの変更が処理された後に保存された永続的な変更トークンです。 -fetchPersistentChanges(since:)このトークンの後に発生した変更を返します。 -changeDetails(for: PHObjectType.asset)写真アセットに関連する変更の詳細のみを取得します。 -updatedLocalIdentifiersdeletedLocalIdentifiersinsertedLocalIdentifiers更新、削除、および追加された資産識別子がそれぞれ与えられます。
  • 処理が完了したら、最後の永続的な変更を追加します。changeToken次回の起動のために保存します。

04:21changeDetails(for:)アセット、アセット コレクション、コレクション リストの 3 種類の写真オブジェクトがサポートされています。このセッション例では、PHObjectType.assetなぜなら、Mountaineering Collage は写真資産自体に関係しているからです。

アプリに関連する変更のみを処理します

(05:55) 変更リストを取得した後も、アプリはフィルタリングする必要があります。登山アプリは写真ライブラリのすべての変更を必要とするわけではなく、新しい写真が特定のハイキング期間内にあるかどうか、使用した写真が編集されているかどうか、使用した写真が削除されているかどうかの 3 つのことだけを気にします。

// Get last stored change token
let changeToken = self.lastStoredToken

// Fetch persistent changes
let persistentChanges = try!
         library.fetchPersistentChanges(since: changeToken)

for persistentChange in persistentChanges {
    // Grab change details and process updates
}

キーポイント:

  • changeTokenアプリが最後に同期した写真ライブラリのステータスを表します。 -library.fetchPersistentChanges(since:)その後の変更を一度に取得します。
  • ループ内のアプリのビジネス ルールに従って変更の詳細を処理し、フォト ライブラリ内のすべての内部変更が UI 作業になるのを回避します。

新しい写真を追加: 挿入された識別子を使用して新しいコラージュを生成します

(06:51) 新しいアセットについては、PhotoKit が提供しています。insertedIdentifiers。アプリはこれらの資産を取り出し、ハイキングの時間範囲を使用して、それらが特定の動きに属しているかどうかを判断できます。

let insertedAssets = PHAsset.fetchAssets(with: insertedIdentifiers, options: nil)
insertedAssets.enumerateObjects { asset, idx, stop in
   for hike in hikes {
        let dateInterval = NSDateInterval(start: hike.startDate, end: hike.endDate)
        if dateInterval.contains(asset.creationDate) {
            // This hike contains a new added asset
        }
    }
}

キーポイント:

  • insertedIdentifiers永続的な変更の詳細から。 -PHAsset.fetchAssets(with:options:)識別子を読み取り可能なものに変換しますPHAsset
  • それぞれhikeすべてに開始時間と終了時間があります。 -NSDateIntervalこれら 2 つの時間を使用して間隔を作成します。 -dateInterval.contains(asset.creationDate)追加された写真がこのハイキングに属するかどうかを判断します。

写真を変更する: hasAdjustments を使用して再描画が必要かどうかを判断します

(07:08) アセットを更新するために、セッションでは新しいhasAdjustmentsAPI。アセットが編集されているかどうかを判断でき、登山アプリはそれを使用して UI で写真を再描画するかどうかを決定します。

let updatedAssets = PHAsset.fetchAssets(with: updatedIdentifiers, options: nil)
updatedAssets.enumerateObjects { asset, idx, stop in
    if asset.hasAdjustments {
        // This asset has edits
    }
}

キーポイント:

  • updatedIdentifiers永続的な変更の詳細から。 -fetchAssetsこれらの更新されたアセットを取得します。 -asset.hasAdjustmentsこのアセットが編集および調整されていることを示します。
  • 条件が満たされると、アプリはこの写真を使用してインターフェースを再レンダリングできます。

写真の削除: 削除された識別子を使用して、再構築するコラージュを見つけます

(07:20) アセットを削除する場合、PhotoKit によって与えられたローカル識別子で十分です。アプリは、存在しないアセットを写真ライブラリから取得する必要がなくなり、どのタイルがこれらの識別子を参照しているかを確認するだけで済みます。

for deletedIdentifier in deletedIdentifiers {
    for collage in collages {
        if collage.assetLocalIdentifiers.contains(deletedIdentifier) {
            // This collage needs to be redrawn
        }
    }
}

キーポイント:

  • deletedIdentifiers削除されたアセットのローカル識別子のコレクションです。 -collagesアプリ内にローカルに保存されたコラージュデータです。 -assetLocalIdentifiersコラージュにどの写真が使用されているかを追跡します。
  • 一致するものを見つけるdeletedIdentifier最後に、コラージュを再生成する必要があります。

エラー処理: トークンの有効期限が切れた場合、または詳細が利用できない場合は再取得します。

(08:20) 永続的な履歴では 2 種類のエラーが返される場合があります。最初のカテゴリはpersistentChangeTokenExpired、トークンが利用可能な履歴よりも古いことを示します。 2番目のカテゴリーは、persistentChangeDetailsUnavailableこれは、この永続的な変更が発生した変更を完全に再構築できないことを示しています。

do {
    let persistentChanges = try library.fetchPersistentChanges(since: changeToken)
} catch PHPhotosError.persistentChangeTokenExpired,
        PHPhotosError.persistentChangeDetailsUnavailable {
    let fetchResult = PHAsset.fetchAssets(with: trackedIdentifiers, options: options)
    // Use fetch result
}

キーポイント:

  • doブロック内でトークンを押して、通常どおり永続的な変更をプルします。 -persistentChangeTokenExpiredアプリは古いトークンを放棄する必要があります。 -persistentChangeDetailsUnavailable現在のフォトライブラリの状態を再確認するにはアプリが必要です。
  • フォールバックスキームが使用されるtrackedIdentifiers追跡されたオブジェクトを再フェッチして、アプリを正しい状態に復元します。

Apple はまた、大量の写真ライブラリの同期や UI をブロックする処理アクティビティを避けるために、変更履歴のクエリをバックグラウンド スレッドに配置することを推奨しています。挿入および更新されたアセットの場合、通常、複数の小さなフェッチよりも 1 回の大きなフェッチの方が適切です。 (07:36)

その他の PhotoKit アップデート

(08:54) セッションの最後には、PhotoKit のいくつかのアップデートについても言及されました。映画のビデオには、メディア サブタイプとスマート アルバムを通じてアクセスできます。写真ライブラリが macOS のファイル プロバイダー同期ルート ディレクトリにある場合のライブラリ破損シナリオと、ネットワークの問題によりアセット リソースが見つからないシナリオをカバーする 2 つの新しいエラー コードが追加されました。


重要ポイント

  • 対処方法: 旅行、スポーツ、または親子のフォト アルバム アプリに写真を自動的に追加します。
    実行する価値がある理由: 永続的な変更履歴により、前回の起動以降にどの写真が追加されたかをアプリに直接伝えることができます。
    開始方法: 保存lastStoredToken、使用insertedLocalIdentifiers新しいアセットを取得し、もう一度押しますcreationDate活動時間帯を合わせてください。

  • 対処方法: ユーザーが写真を編集した後に、写真のコラージュ、カバー画像、またはタイムラインが自動的に更新されるようにします。
    実行する価値がある理由:updatedLocalIdentifiersそしてhasAdjustments編集中のアセットを見つけることができます。
    開始方法: 各 UI モジュールによって参照されるアセットのローカル識別子を維持し、更新を検出した後にのみ、影響を受けるモジュールを再描画します。

  • 内容: フォト アルバムの主催者向けに、削除を意識したローカル インデックスを作成します。
    実行する価値がある理由:deletedLocalIdentifiers削除されたアセットは、完全な差分を繰り返すことなく直接表示されます。
    開始方法: ローカル データベースには資産のローカル識別子が保存されます。削除された識別子を受け取ったら、インデックスをクリーンアップするか、再構築用にマークを付けます。

  • 対処方法: 長期間開かれていない写真アプリ用のバックグラウンド同期ポータルを作成します。
    実行する価値がある理由: 永続的な履歴には、アプリが非アクティブなときに長期間にわたる変更が記録されます。
    開始方法: バックグラウンドキューで呼び出しますfetchPersistentChanges(since:)、ビジネスに必要な資産、資産コレクション、またはコレクション リストへの変更のみを処理します。

  • 対処方法: 制限付きライブラリ モードで写真機能を増分更新します。
    実行する価値がある理由: PhotoKit は、ユーザーが選択したオブジェクトへの変更のみを返します。これは、権限が小さいアプリに適しています。
    開始方法: アプリが写真ライブラリ全体にアクセスできることを想定せずに、トークンとローカル識別子に基づいて同期ロジックを構築します。


関連セッション

コメント

GitHub Issues · utterances