PhotoKit — це фреймворк Apple для роботи з медіатекою на iOS та macOS, що надає прямий доступ до фото, відео та Live Photos на пристрої. За даними документації Apple, фреймворк замінює застарілий AssetsLibrary та підтримує iCloud, альбоми, редагування та Change Tracking. PhotoKit забезпечує єдиний API для запитів, кешування та змін медіатеки з автоматичною синхронізацією через iCloud.
Головне
PhotoKit — фреймворк Apple (представлений в iOS 8, macOS 10.11), що надає об'єктно-орієнтований API для роботи з системною медіатекою. На відміну від AssetsLibrary, PhotoKit працює з медіатекою як з базою даних: запити повертають об'єкти PHAsset, PHCollection та PHCollectionList, що представляють вміст та структуру зберігання.
PhotoKit підтримує всі типи медіа: фотографії (JPEG, HEIF, RAW), відео (MOV, MP4), Live Photos та серійні знімки. Фреймворк автоматично керує синхронізацією iCloud: якщо зображення зберігається в iCloud, PhotoKit запитує його через мережу та повідомляє прогрес через PHImageRequestOptions.progressHandler.
Ключова особливість PhotoKit — модель даних на основі PHObject з локальним ідентифікатором (localIdentifier), який залишається стабільним між сесіями. Це дозволяє зберігати посилання на медіа-об'єкти та відновлювати їх після перезапуску додатку без повторного запиту.
PhotoKit побудований на трьох рівнях: моделі даних (PHObject), запитів (PHFetchResult) та змін (PHPhotoLibrary.performChanges). Модель даних ієрархічна: PHAsset (фото/відео) знаходиться всередині PHAssetCollection (альбом), альбоми групуються в PHCollectionList (папка).
Запити виконуються через PHAsset.fetchAssets та PHAssetCollection.fetchAssetCollections. Всі методи fetch — синхронні і повертають PHFetchResult, об'єкт якого одразу виконує запит до бази даних медіатеки. PHFetchResult підтримує швидкий доступ за індексом (object(at:)) та перелік через enumerateObjects.
PHFetchOptions — об'єкт для конфігурації запиту: сортування (sortDescriptors), предикат (predicate), включення прихованих та видалених медіа (includeHiddenAssets, includeAllBurstAssets). Fetch-опції дозволяють фільтрувати за типом медіа: PHAssetMediaType.image, .video, .audio.
PhotoKit включає набір класів для доступу, запитів та зміни медіатеки. Розуміння кожного з них необхідне для ефективної роботи з фреймворком.
PHAsset — незмінний об'єкт, що представляє один медіа-об'єкт. Містить метадані: mediaType, mediaSubtypes, creationDate, location, pixelWidth, pixelHeight, duration (для відео), isFavorite, burstIdentifier. LocalIdentifier — стабільний рядковий ключ, доступний навіть після перезапуску додатку.
PHAssetCollection — група медіа: системні альбоми (Recents, Favorites, Selfies, Screenshots), користувацькі альбоми або Moments (автоматично згруповані за часом та місцем). Атрибути: localizedTitle, assetCollectionType, assetCollectionSubtype, startDate, endDate.
PHCollectionList — папка, що містить альбоми (PHAssetCollection) або інші папки. Використовується рідко, в основному для відображення ієрархії в інтерфейсі користувача.
PhotoKit не повертає UIImage безпосередньо з PHAsset — потрібно запросити зображення через PHImageManager. Це гарантує, що зображення завантажується з урахуванням iCloud, кешування та необхідного розміру.
| Компонент | Призначення | Особливість |
|---|---|---|
| PHImageManager.default() | Стандартний менеджер для разових запитів | Немає кешування між запитами |
| PHCachingImageManager | Менеджер з попереднім завантаженням для колекцій | startCachingImages для плавного скролу |
| PHImageRequestOptions | Налаштування запиту: розмір, режим, доставка | synchronous, deliveryMode, progressHandler |
| PHImageRequestID | Ідентифікатор запиту для скасування | cancelImageRequest(PHImageRequestID) |
PHImageManager підтримує три режими доставки: opportunistic (спочатку зменшена версія, потім повна), highQualityFormat (тільки повна якість) та fastFormat (найшвидша доступна версія). Для колекцій завжди використовуйте PHCachingImageManager з попереднім завантаженням зображень для видимих комірок.
PhotoKit використовується для створення користувацьких галерей, редакторів та додатків для роботи з медіа. Розглянемо три ключові сценарії.
PHAsset.fetchAssets з PHFetchOptions та сортуванням за датою створення — базовий запит для побудови користувацької фотогалереї. PHFetchResult підтримує lazy-loading та потоковий доступ.
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("Знайдено \(allPhotos.count) фото")
allPhotos.enumerateObjects { asset, index, stop in
print("Фото \(index): \(asset.localIdentifier)")
}
PHFetchResult — потокобезпечний контейнер. Доступ до об'єктів за індексом через object(at:) не блокує UI, але запит зображення через PHImageManager повинен виконуватися асинхронно.
PHCachingImageManager — підклас PHImageManager з методами startCachingImages та stopCachingImages для попереднього завантаження. Використовується в UICollectionView для плавного скролу.
let cachingManager = PHCachingImageManager()
let targetSize = CGSize(width: 200, height: 200)
// Попереднє завантаження для видимих комірок
cachingManager.startCachingImages(
for: visibleAssets,
targetSize: targetSize,
contentMode: .aspectFill,
options: nil
)
// Запит зображення через PHImageRequestOptions з iCloud fallback
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .opportunistic
requestOptions.isNetworkAccessAllowed = .true
requestOptions.progressHandler = { progress, error, stop, info in
DispatchQueue.main.async {
print("Завантаження з iCloud: \(progress * 100)%")
}
}
let requestID = cachingManager.requestImage(
for: asset,
targetSize: targetSize,
contentMode: .aspectFill,
options: requestOptions
) { image, info in
print("Отримано зображення: \(image?.size ?? .zero)")
}
Зміни в медіатеці виконуються через PHPhotoLibrary.shared().performChanges всередині блоку changeRequest. Всі операції батчаться та застосовуються транзакційно.
PHPhotoLibrary.shared().performChanges {
let changeRequest = PHAssetChangeRequest(for: asset)
changeRequest.isFavorite = .true
} completionHandler: { success, error in
if success {
print("Додано до обраного")
}
}
PhotoKit надає механізм спостереження за змінами медіатеки через протокол PHPhotoLibraryChangeObserver. При будь-яких змінах (створення, видалення, редагування) викликається метод photoLibraryDidChange з об'єктом PHChange.
PHChange містить changeDetails для кожного типу запиту: PHFetchResultChangeDetails з removedIndexes, insertedIndexes, changedIndexes. Це дозволяє застосовувати зміни до UI з анімацією: performBatchUpdates з move, insert, delete для 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
// Застосувати зміни до collectionView
}
}
}
PhotoKit підтримує редагування медіа через механізм PHContentEditingInput та PHContentEditingOutput. Додаток запитує editingInput з вихідними даними, застосовує зміни та зберігає результат через editingOutput. Фреймворк автоматично зберігає оригінал, дозволяючи користувачеві відкотити зміни через скидання до оригіналу.
RAW-фотографії (DNG, CR2, NEF) підтримуються через PHAssetResourceManager, який надає доступ до вихідного RAW-файлу. Для обробки RAW рекомендується використовувати CoreImage з фільтром CIRAWFilter, який підтримує налаштування температури, експозиції та різкості. PhotoKit також підтримує розширення редакторів через Photo Editing Extension (iOS) — додаток може бути викликаний із системного редактора для обробки вибраного фото або відео.
PhotoKit — потужний, але ресурсоємний фреймворк. Неправильне використання може призводити до гальмування при скролі та надмірного витрачання пам'яті. Дотримуйтесь рекомендацій для оптимальної продуктивності.
PHLivePhoto — потребує окремого запиту через PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:). Не запитуйте Live Photo для комірок, де відображається тільки фото — використовуйте PHLivePhotoBadge для індикації.
Поширені запитання
PhotoKit — сучасний фреймворк Apple для роботи з медіатекою, представлений в iOS 8. На відміну від застарілого AssetsLibrary, PhotoKit надає об'єктну модель PHAsset, PHFetchResult зі швидким пошуком, підтримку iCloud та Change Tracking для спостереження за змінами.
Викличте PHPhotoLibrary.requestAuthorization(for: .readWrite) з обробкою в колбеку. Після отримання статусу .authorized можна виконувати запити PHAsset.fetchAssets. Для запису потрібен доступ .readWrite. Для лише читання — .addOnly.
Використовуйте PHImageManager.default().requestImage з параметрами: asset, targetSize, contentMode та PHImageRequestOptions. Асинхронний метод повертає PHImageRequestID, що дозволяє скасувати запит. Для колекцій використовуйте PHCachingImageManager з попереднім завантаженням.
Зареєструйте спостерігача через PHPhotoLibrary.shared().register(self) та реалізуйте протокол PHPhotoLibraryChangeObserver. В методі photoLibraryDidChange отримайте PHChange з changeDetails для кожного fetchResult та застосуйте зміни до UI з анімацією.
В PHImageRequestOptions встановіть isNetworkAccessAllowed = true та progressHandler для відстеження завантаження з iCloud. При швидкому скролі відключайте мережевий доступ та завантажуйте тільки локальні версії, щоб уникнути затримок при скролі.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також