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不直接从PHAsset返回UIImage — 需要通过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 — 线程安全容器。通过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回退
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中动画应用更改:针对UICollectionView执行带有move、insert、delete的performBatchUpdates。
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处理,建议使用带有CIRAWFilter过滤器的CoreImage,该过滤器支持调整温度、曝光和锐度。PhotoKit还通过Photo Editing Extension(iOS)支持编辑器扩展 — 应用程序可以从系统编辑器调用以处理选定的照片或视频。
PhotoKit — 一个强大但资源密集型的框架。不正确的使用可能导致滚动时卡顿和内存过度消耗。遵循以下建议以获得最佳性能。
PHLivePhoto — 需要通过PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:)进行单独请求。不要为仅显示照片的单元格请求Live Photo — 使用PHLivePhotoBadge进行指示。
常见问题
PhotoKit — 苹果用于处理媒体库的现代框架,在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方法中,您将收到带有每个fetchResult的changeDetails的PHChange,并在UI中动画应用更改。
在PHImageRequestOptions中设置isNetworkAccessAllowed = true和progressHandler以跟踪从iCloud的加载。快速滚动时禁用网络访问,仅加载本地版本以避免滚动延迟。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。