스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
PhotoKit 변경 내역 살펴보기
PhotoKit을 통해 풍부한 사진 중심 기능을 빌드할 수 있습니다. PhotoKit의 최신 API를 통해 이미지 자산의 변경 내용을 쉽게 추적하는 방법을 알아보세요. PHPhotoLibrary 변경 내역 API를 소개하고, 출시 간 변경 토큰을 보존하여 앱에서 사용자의 사진 라이브러리에 대한 추가 사항, 삭제 및 업데이트를 인식하는 방법을 시연합니다. 사진 라이브러리 통합에 대해 자세히 알아보려면 WWDC22의 ‘What's new in the Photos picker(Photos 선택기의 새로운 기능)' 및 WWDC21의 ‘Improve access to Photos in your app(앱에서 Photos 액세스 개선)'을 시청하시기 바랍니다.
리소스
관련 비디오
WWDC23
WWDC22
WWDC21
-
다운로드
♪ 부드러운 힙합 음악 ♪ ♪ 안녕하세요, 전 Mindy입니다 Photos 팀 엔지니어죠 오늘은 앱에서 Photos 변경 기록에 접근하는 방법에 대해 알아볼게요 PhotoKit은 풍부한 API 집합을 제공합니다 사진 라이브러리에 저장된 사진, 영상 및 앨범에 접근하고 업데이트하기 위해서죠 PhotoKit는 심층적인 수준으로 Photos 접근과 통합이 필요한 앱을 위해 설계됐습니다 사진 관리, 편집 사용자 지정 카메라 앱이나 사진 라이브러리를 독특하게 탐색할 수 있는 방법을 제공하는 앱들이죠 이런 유형의 앱들은 사진 라이브러리가 시간이 지남에 따라 어떻게 변경되는지 모니터링해서 Photos의 경험을 자세히 반영할 수 있죠 제가 소셜 하이킹 앱을 만들었다고 해 보죠 친구와 하이킹에 다녀온 사진을 공유하고 편집하는 앱입니다 누군가 그 앱을 시작하면 산에서의 경험을 콜라주로 만들기 위해 최근 하이킹 운동의 시작과 끝 타임스탬프에서 사진을 모읍니다 콜라주는 사진 라이브러리에서 선택한 사진과 동기화된 상태로 유지되죠 예를 들어 친구한테서 하이킹 사진을 받는다면 앱은 이 업데이트를 사용해 새로운 콜라주를 생성할 겁니다 지금까지 앱이 새로 삽입된 자산과 이전 하이킹 콜라주의 변경 사항을 발견하려면 일련의 가져오기를 수행해야 했죠 어떤 자산이 삽입됐는지 확인하기 위해서 앱은 마지막 앱 실행 날짜보다 늦게 생성된 자산을 가져올 수 있습니다 자산 업데이트 및 삭제를 결정하는 건 더 어렵죠 앱은 모든 콜라주에 있는 모든 자산을 다시 가져오고 자산 업데이트를 확인하기 위해 수정 날짜를 확인해야 하는데 Photos 내부의 처리 활동 때문에 자산 수정 날짜가 바뀔 수 있기 때문에 잘못 탐지할 가능성이 있습니다 사진 라이브러리의 삭제는 추적이 더 어렵습니다 추적된 모든 자산을 가져와야 하고 함께 반환되지 않은 자산을 비교해야 하기 때문이죠 전체적으로 앱을 실행할 때마다 세 가지 검사를 별도로 수행해야 하는데 앱이 많은 양의 자산을 표시하는 경우 특히나 비용이 많이 듭니다 불확실한 결과를 일일이 가져오기 및 확인을 하는 대신 한 번의 통합 API 호출로 무엇이 변했는지 정확하게 아는 방법이 있다면 어떨까요? 우리가 바로 그 기능을 구현해 냈습니다 새로운 변경 내역 API를 통해 사진 라이브러리의 오프라인 업데이트를 더 쉽게 추적할 수 있습니다 변경 내역은 사진 라이브러리에 대한 삽입, 업데이트, 삭제처럼 변경 사항의 타임라인으로 구성되죠 여기 타임라인 예시를 보면 지난 3일간의 변경 내역에 다양한 자산, 앨범, 폴더가 변경됐습니다 이 타임라인을 사용해서 지난 이틀 또는 마지막으로 앱을 실행한 시간부터 변경 사항이 발생한 걸 어떻게 확인할 수 있을까요? 이제 영구 변경 토큰을 사용하면 됩니다 특정 시점 사진 라이브러리의 상태를 나타내는 토큰이죠 이 토큰은 앱을 실행해도 유지되고 해당 토큰 이후 발생한 변경 사항을 사진 라이브러리에서 가져오는 데 사용할 수 있습니다 타사 앱 변경 사항도 포함하죠 여러분의 앱이 제한된 라이브러리 모드일 땐 사용자가 선택한 PhotoKit 개체에 대한 변경 사항만 반환됩니다 이 변경 토큰은 장치에 로컬이며 언제든지 영구 변경 사항이나 사진 라이브러리 인스턴스에서 접근할 수 있습니다 이 새로운 API는 PhotoKit를 지원하는 모든 플랫폼 즉 macOS, iOS, iPadOS tvOS에서 사용 가능합니다 앱이 실행되고 사진 라이브러리와 함께 작동하면 앱에 영구 변경 토큰을 저장할 수 있죠 나중에 이 토큰을 사용해 사진 라이브러리에서 이후에 발생한 변경 사항을 가져올 수 있습니다 각각의 영구 변경 사항에 대해 Photos 개체에 대한 변경 세부 정보를 세 가지 유형으로 가져올 수 있습니다 자산, 자산 수집, 수집 목록이죠 코드에서는 어떻게 보일까요? 마지막으로 저장된 변경 토큰을 사용해 영구 변경 사항을 가져옵니다 다음은 영구 변경 내용을 열거하고 각 영구 변경 개체에 대한 변경 세부 정보를 가져옵니다 이 경우엔 자산 유형이죠 이런 변경 세부 정보는 변경 토큰 이후에 사진 라이브러리에서 업데이트, 삭제, 삽입된 로컬 식별자에 대한 정보를 제공합니다 이 변경 사항을 처리하고 마지막 변경 토큰을 저장해 나중에 사용할 수 있습니다 새로운 영구 이력 API와 기존의 변경 관찰자 API를 비교하고 대조해 볼게요 PHChanges는 활성 메모리 내 가져오기 결과를 처리해서 앱이 실행되는 동안 사진 라이브러리에 실시간 변경 사항을 기록하는 데 사용됩니다 반면 영구 이력은 사진 라이브러리에 장기 실행 중인 변경 사항을 기록하고 앱의 활성화가 끝난 이후의 변경 사항을 보고하는 데 사용할 수 있습니다 여러분은 앱의 요구 사항에 따라 두 API를 모두 사용하거나 하나만 사용할 수 있죠 하이킹 앱의 예시로 돌아가 보죠 저는 이제 하이킹 몰라주를 만들고 업데이트하기 위해 영구 이력 API를 사용해서 자산 변동을 추적하려고 합니다 먼저 마지막으로 저장된 변경 토큰을 사용해 영구 변경 사항을 가져옵니다 다음으로 영구 변경 사항 처리 절차를 반복해 관련 자산의 변경 세부 정보를 파악한 후 삽입, 업데이트, 삭제된 식별자를 처리할게요 이제 변경 내역에서 앱에 영향을 미치는 라이브러리 변경 사항을 식별해야 합니다 변경 사항을 가져오면 반환되는 모든 정보가 앱에 필요하진 않으니까요 앱이 사진 라이브러리에서 새로운 하이킹 때문에 추가된 자산을 식별하고 이전 하이킹 콜라주에서 참조한 자산의 업데이트와 삭제를 아는 게 중요합니다 저는 영구 변경 사항을 열거한 데서 삽입, 업데이트, 삭제된 자산의 로컬 식별자를 이미 3세트 식별했습니다 어떻게 이걸 반영해 업데이트할까요? insertedIdentifiers 세트를 사용해서 삽입된 자산을 가져오고 하이킹 시작, 종료와 자산의 생성 날짜를 비교하면서 하이킹 타임스탬프 사이에 어떤 자산이 추가됐는지 확인할 수 있습니다 업데이트된 자산에 조정이 적용됐을 수 있으니 새 hasAdjustments API를 사용해 UI에서 자산을 다시 그려야 하는지 확인할 수 있습니다 삭제된 자산 로컬 식별자를 사용해 재생성해야 하는 콜라주를 결정할 수 있죠 이제 오프라인 사진 라이브러리의 변경 사항을 모두 처리했고 앱이 최신 상태입니다 새로운 변경 내역 API를 다룰 때 주의해야 할 사항이 몇 가지 있습니다 먼저 사용자와 앱에 중요한 변경 사항을 결정하고 변경 사항만 확인합니다 업데이트, 삽입된 자산에 대해 성능 향상을 위해서는 여러 개의 작은 요청 대신 하나의 큰 가져오기 요청을 수행하는 게 좋습니다 사진 라이브러리는 보이지 않는 곳에서 처리 및 동기화 활동으로 많이 변경될 수 있기 때문에 앱이 자주 실행되지 않는 경우엔 많은 양의 변경 사항을 열거하게 될 수 있습니다 그래서 우리는 UI가 차단되지 않도록 배경 스레드에서 변경 내역 요청을 권합니다 영구 이력을 가져올 때 발생할 수 있는 오류가 두 가지 있습니다 변경 토큰이 가능한 변경 내역보다 오래된 경우 만료된 변경 토큰 오류가 반환됩니다 어떤 경우에는 영구 변경 사항이 발생한 변경 사항을 완전히 재구성했는지 확신할 수 없고 변경 세부 정보를 쓸 수 없다는 오류를 반환할 수도 있습니다 이 경우 앱이 최신 상태인지 확인하기 위해 사진 라이브러리에서 추적된 개체를 다시 가져오는 걸 추천할게요 마무리하기 전에 여러분과 공유하고 싶은 새 PhotoKit API가 몇 가지 더 있어요 PhotoKit은 미디어 하위 유형 및 스마트 앨범에서 이제 시네마틱 영상 접근을 지원합니다 새로운 오류 코드도 두 가지 있습니다 사진 라이브러리 번들이 macOS의 File Provider 동기화 루트 디렉토리에 있는 경우 라이브러리가 손상될 수 있고 변경 작업을 수행할 때 오류가 반환됩니다 네트워크 문제로 자산 리소스를 찾을 수 없는 경우 리소스 요청에 네트워크 오류가 반환됩니다 개발자 문서를 보고 모든 최신 업데이트를 확인하세요 마지막으로 Photos 피커에 관한 올해의 세션을 확인하세요 Photos를 사용하고 접근하는 가장 쉬운 방법입니다 여러분이 새로운 변경 내역 API와 PhotoKit의 모든 신기능을 사용할 수 있어 기분이 좋네요 감사합니다 ♪
-
-
0:01 - Tracking photo library changes
// Discover added assets let options = PHFetchOptions() options.predicate = NSPredicate(format: "creationDate > %@", lastLaunchDate as CVarArg) let insertedAssets = PHAsset.fetchAssets(with: options)
-
0:02 - Tracking photo library changes (2)
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 } }
-
0:03 - Fetching persistent changes using persistent change token
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
-
0:04 - Identifying important changes
// 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 }
-
0:05 - Using inserted identifiers
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 } } }
-
0:06 - Using updated identifiers
let updatedAssets = PHAsset.fetchAssets(with: updatedIdentifiers, options: nil) updatedAssets.enumerateObjects { asset, idx, stop in if asset.hasAdjustments { // This asset has edits } }
-
0:07 - Using deleted identifiers
for deletedIdentifier in deletedIdentifiers { for collage in collages { if collage.assetLocalIdentifiers.contains(deletedIdentifier) { // This collage needs to be redrawn } } }
-
0:08 - Handling errors
do { let persistentChanges = try library.fetchPersistentChanges(since: changeToken) } catch PHPhotosError.persistentChangeTokenExpired, PHPhotosError.persistentChangeDetailsUnavailable { let fetchResult = PHAsset.fetchAssets(with: trackedIdentifiers, options: options) // Use fetch result }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.