PhotoKit — to framework Apple do pracy z biblioteką multimediów na iOS i macOS, zapewniający bezpośredni dostęp do zdjęć, filmów i Live Photos na urządzeniu. Według dokumentacji Apple, framework zastępuje przestarzały AssetsLibrary i obsługuje iCloud, albumy, edycję oraz Change Tracking. PhotoKit zapewnia jednolity API do zapytań, buforowania i zmian w bibliotece multimediów z automatyczną synchronizacją przez iCloud.
Najważniejsze
PhotoKit — framework Apple (wprowadzony w iOS 8, macOS 10.11), zapewniający zorientowany obiektowo API do pracy z systemową biblioteką multimediów. W przeciwieństwie do AssetsLibrary, PhotoKit traktuje bibliotekę multimediów jak bazę danych: zapytania zwracają obiekty PHAsset, PHCollection, PHCollectionList, reprezentujące zawartość i strukturę przechowywania.
PhotoKit obsługuje wszystkie typy multimediów: zdjęcia (JPEG, HEIF, RAW), wideo (MOV, MP4), Live Photos i zdjęcia seryjne. Framework automatycznie zarządza synchronizacją iCloud: jeśli obraz jest przechowywany w iCloud, PhotoKit pobiera go przez sieć i raportuje postęp przez PHImageRequestOptions.progressHandler.
Kluczową cechą PhotoKit jest model danych oparty na PHObject z lokalnym identyfikatorem (localIdentifier), który pozostaje stabilny między sesjami. Umożliwia to zapisywanie odniesień do obiektów multimedialnych i przywracanie ich po ponownym uruchomieniu aplikacji bez ponownego zapytania.
PhotoKit jest zbudowany na trzech poziomach: modelu danych (PHObject), zapytań (PHFetchResult) i zmian (PHPhotoLibrary.performChanges). Model danych jest hierarchiczny: PHAsset (zdjęcie/wideo) znajduje się wewnątrz PHAssetCollection (album), albumy są grupowane w PHCollectionList (folder).
Zapytania są wykonywane przez PHAsset.fetchAssets i PHAssetCollection.fetchAssetCollections. Wszystkie metody fetch są synchroniczne i zwracają PHFetchResult, którego obiekt natychmiast wykonuje zapytanie do bazy danych biblioteki multimediów. PHFetchResult obsługuje szybki dostęp po indeksie (object(at:)) i wyliczanie przez enumerateObjects.
PHFetchOptions — obiekt do konfiguracji zapytania: sortowanie (sortDescriptors), predykat (predicate), uwzględnianie ukrytych i usuniętych multimediów (includeHiddenAssets, includeAllBurstAssets). Opcje fetch pozwalają filtrować po typie medium: PHAssetMediaType.image, .video, .audio.
PhotoKit zawiera zestaw klas do dostępu, zapytań i zmiany biblioteki multimediów. Zrozumienie każdej z nich jest niezbędne do efektywnej pracy z frameworkiem.
PHAsset — niezmienny obiekt reprezentujący pojedyncze medium. Zawiera metadane: mediaType, mediaSubtypes, creationDate, location, pixelWidth, pixelHeight, duration (dla wideo), isFavorite, burstIdentifier. LocalIdentifier — stabilny klucz tekstowy, dostępny nawet po ponownym uruchomieniu aplikacji.
PHAssetCollection — grupa multimediów: albumy systemowe (Recents, Favorites, Selfies, Screenshots), albumy użytkownika lub Moments (automatycznie grupowane według czasu i miejsca). Atrybuty: localizedTitle, assetCollectionType, assetCollectionSubtype, startDate, endDate.
PHCollectionList — folder zawierający albumy (PHAssetCollection) lub inne foldery. Używany rzadko, głównie do wyświetlania hierarchii w interfejsie użytkownika.
PhotoKit nie zwraca UIImage bezpośrednio z PHAsset — trzeba pobrać obraz przez PHImageManager. Gwarantuje to, że obraz jest ładowany z uwzględnieniem iCloud, buforowania i wymaganego rozmiaru.
| Komponent | Przeznaczenie | Cecha |
|---|---|---|
| PHImageManager.default() | Standardowy menedżer do pojedynczych zapytań | Brak buforowania między zapytaniami |
| PHCachingImageManager | Menedżer z preładowaniem dla kolekcji | startCachingImages dla płynnego przewijania |
| PHImageRequestOptions | Ustawienia zapytania: rozmiar, tryb, dostawa | synchronous, deliveryMode, progressHandler |
| PHImageRequestID | Identyfikator zapytania do anulowania | cancelImageRequest(PHImageRequestID) |
PHImageManager obsługuje trzy tryby dostawy: opportunistic (najpierw zmniejszona wersja, potem pełna), highQualityFormat (tylko pełna jakość) i fastFormat (najszybsza dostępna wersja). Dla kolekcji zawsze używaj PHCachingImageManager z preładowaniem obrazów dla widocznych komórek.
PhotoKit jest używany do tworzenia niestandardowych galerii, edytorów i aplikacji do pracy z multimediami. Rozważmy trzy kluczowe scenariusze.
PHAsset.fetchAssets z PHFetchOptions i sortowaniem według daty utworzenia — podstawowe zapytanie do budowania niestandardowej galerii zdjęć. PHFetchResult obsługuje lazy-loading i dostęp strumieniowy.
let options = PHFetchOptions()
options.sortDescriptors = [NSSortDescriptor(
key: "creationDate",
ascending: .false
)]
options.predicate = NSPredicate(
format: "mediaType == %d",
PHAssetMediaType.image.rawValue
)
let allPhotos = PHAsset.fetchAssets(with: options)
print("Znaleziono \(allPhotos.count) zdjęć")
allPhotos.enumerateObjects { asset, index, stop in
print("Zdjęcie \(index): \(asset.localIdentifier)")
}
PHFetchResult — bezpieczny wątkowo kontener. Dostęp do obiektów po indeksie przez object(at:) nie blokuje UI, ale pobranie obrazu przez PHImageManager musi być wykonane asynchronicznie.
PHCachingImageManager — podklasa PHImageManager z metodami startCachingImages i stopCachingImages do preładowania. Używany w UICollectionView do płynnego przewijania.
let cachingManager = PHCachingImageManager()
let targetSize = CGSize(width: 200, height: 200)
// Preładowanie dla widocznych komórek
cachingManager.startCachingImages(
for: visibleAssets,
targetSize: targetSize,
contentMode: .aspectFill,
options: nil
)
// Pobranie obrazu przez PHImageRequestOptions z iCloud fallback
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .opportunistic
requestOptions.isNetworkAccessAllowed = .true
requestOptions.progressHandler = { progress, error, stop, info in
DispatchQueue.main.async {
print("Pobieranie z iCloud: \(progress * 100)%")
}
}
let requestID = cachingManager.requestImage(
for: asset,
targetSize: targetSize,
contentMode: .aspectFill,
options: requestOptions
) { image, info in
print("Otrzymano obraz: \(image?.size ?? .zero)")
}
Zmiany w bibliotece multimediów są wykonywane przez PHPhotoLibrary.shared().performChanges wewnątrz bloku changeRequest. Wszystkie operacje są grupowane i stosowane transakcyjnie.
PHPhotoLibrary.shared().performChanges {
let changeRequest = PHAssetChangeRequest(for: asset)
changeRequest.isFavorite = .true
} completionHandler: { success, error in
if success {
print("Dodano do ulubionych")
}
}
PhotoKit zapewnia mechanizm obserwacji zmian w bibliotece multimediów przez protokół PHPhotoLibraryChangeObserver. Przy każdej zmianie (tworzenie, usuwanie, edycja) wywoływana jest metoda photoLibraryDidChange z obiektem PHChange.
PHChange zawiera changeDetails dla każdego typu zapytania: PHFetchResultChangeDetails z removedIndexes, insertedIndexes, changedIndexes. Umożliwia to zastosowanie zmian w UI z animacją: performBatchUpdates z move, insert, delete dla UICollectionView.
class PhotosViewController: UIViewController {
var fetchResult: PHFetchResult>PHAsset>?
override func viewDidLoad() {
super.viewDidLoad()
PHPhotoLibrary.shared().register(self)
}
deinit {
PHPhotoLibrary.shared().unregisterChangeObserver(self)
}
}
extension PhotosViewController: PHPhotoLibraryChangeObserver {
func photoLibraryDidChange(_ changeInstance: PHChange) {
guard let fetchResult,
let details = changeInstance.changeDetails(for: fetchResult)
else { return }
DispatchQueue.main.async {
self.fetchResult = details.fetchResultAfterChanges
// Zastosuj zmiany do collectionView
}
}
}
PhotoKit obsługuje edycję multimediów przez mechanizm PHContentEditingInput i PHContentEditingOutput. Aplikacja żąda editingInput z oryginalnymi danymi, stosuje zmiany i zapisuje wynik przez editingOutput. Framework automatycznie zachowuje oryginał, umożliwiając użytkownikowi przywrócenie zmian przez reset do oryginału.
Zdjęcia RAW (DNG, CR2, NEF) są obsługiwane przez PHAssetResourceManager, który zapewnia dostęp do oryginalnego pliku RAW. Do przetwarzania RAW zaleca się użycie CoreImage z filtrem CIRAWFilter, który obsługuje regulację temperatury, ekspozycji i ostrości. PhotoKit obsługuje również rozszerzenia edytorów przez Photo Editing Extension (iOS) — aplikacja może być wywołana z systemowego edytora do przetwarzania wybranego zdjęcia lub filmu.
PhotoKit — potężny, ale zasobożerny framework. Niewłaściwe użycie może prowadzić do spowolnień podczas przewijania i nadmiernego zużycia pamięci. Postępuj zgodnie z zaleceniami dla optymalnej wydajności.
PHLivePhoto — wymaga osobnego zapytania przez PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:). Nie żądaj Live Photo dla komórek, gdzie wyświetlane jest tylko zdjęcie — używaj PHLivePhotoBadge do oznaczenia.
Często zadawane pytania
PhotoKit — nowoczesny framework Apple do pracy z biblioteką multimediów, wprowadzony w iOS 8. W przeciwieństwie do przestarzałego AssetsLibrary, PhotoKit zapewnia model obiektowy PHAsset, PHFetchResult z szybkim wyszukiwaniem, obsługę iCloud oraz Change Tracking do obserwacji zmian.
Wywołaj PHPhotoLibrary.requestAuthorization(for: .readWrite) z obsługą w callbacku. Po uzyskaniu statusu .authorized można wykonywać zapytania PHAsset.fetchAssets. Do zapisu wymagany jest dostęp .readWrite. Tylko do odczytu — .addOnly.
Użyj PHImageManager.default().requestImage z parametrami: asset, targetSize, contentMode i PHImageRequestOptions. Asynchroniczna metoda zwraca PHImageRequestID, umożliwiający anulowanie zapytania. Dla kolekcji używaj PHCachingImageManager z preładowaniem.
Zarejestruj obserwatora przez PHPhotoLibrary.shared().register(self) i zaimplementuj protokół PHPhotoLibraryChangeObserver. W metodzie photoLibraryDidChange otrzymasz PHChange z changeDetails dla każdego fetchResult i zastosuj zmiany w UI z animacją.
W PHImageRequestOptions ustaw isNetworkAccessAllowed = true i progressHandler do śledzenia pobierania z iCloud. Przy szybkim przewijaniu wyłączaj dostęp sieciowy i ładuj tylko lokalne wersje, aby uniknąć opóźnień podczas przewijania.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również