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 поддържа мързеливо зареждане и поточен достъп.
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 — thread-safe контейнер. Достъпът до обекти по индекс чрез 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) с обработка в callback. След получаване на статус .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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също