PhotoKit — 什么是它,核心概念以及PHAsset

作者: IT Sectr 发布日期: 2026-05-06 阅读时间: 8 分钟

PhotoKit — 是Apple的框架,用于在iOS和macOS上处理媒体库,提供对设备上照片、视频和Live Photos的直接访问。根据Apple文档,该框架取代了已过时的AssetsLibrary,并支持iCloud、相册、编辑和Change Tracking。PhotoKit 为查询、缓存和媒体库更改提供统一的API,通过iCloud自动同步。

要点

  • PhotoKit — Apple用于处理系统媒体库的框架,提供对照片、视频、Live Photos和相册的访问。
  • PHAsset — 表示单个媒体内容(照片或视频)的数据模型,带有元数据:日期、位置、类型。
  • PHFetchResult — 查询结果的容器,支持流式加载和通过PHPhotoLibraryChangeObserver发送更改通知。
  • PHImageManager — 用于获取图像的管理器,支持通过PHCachingImageManager进行大小、模式和缓存选项设置。
  • PHPhotoLibrary — 执行更改的入口点:创建、删除和编辑媒体对象。

什么是PhotoKit?

PhotoKit — Apple框架(在iOS 8、macOS 10.11中引入),提供面向对象的API用于处理系统媒体库。与AssetsLibrary不同,PhotoKit将媒体库视为数据库:查询返回代表内容和存储结构的PHAssetPHCollectionPHCollectionList对象。

PhotoKit支持所有媒体类型:照片(JPEG、HEIF、RAW)、视频(MOV、MP4)、Live Photos和连拍照片。该框架自动管理iCloud同步:如果图像存储在iCloud中,PhotoKit通过网络请求它并通过PHImageRequestOptions.progressHandler报告进度。

PhotoKit的关键特性 — 基于PHObject的数据模型,带有本地标识符(localIdentifier),该标识符在会话之间保持稳定。这允许保存对媒体对象的引用,并在应用程序重启后无需重新查询即可恢复它们。

PhotoKit如何工作:数据模型与查询

PhotoKit构建在三个层次上:数据模型(PHObject)、查询(PHFetchResult)和更改(PHPhotoLibrary.performChanges)。数据模型是分层的:PHAsset(照片/视频)位于PHAssetCollection(相册)内,相册分组在PHCollectionList(文件夹)中。

执行查询

查询通过PHAsset.fetchAssetsPHAssetCollection.fetchAssetCollections执行。所有fetch方法都是同步的,并返回PHFetchResult,其对象立即对媒体库数据库执行查询。PHFetchResult支持基于索引的快速访问(object(at:))和通过enumerateObjects进行枚举。

  • fetchAssets(with:options:) — 查询所有媒体,按类型、日期、相册过滤
  • fetchAssetCollections(with:subtype:options:) — 查询相册和文件夹
  • fetchAssets(in:options:) — 查询特定相册内的媒体

PHFetchOptions

PHFetchOptions — 用于配置查询的对象:排序(sortDescriptors)、谓词(predicate)、包含隐藏和已删除的媒体(includeHiddenAssets、includeAllBurstAssets)。Fetch选项允许按媒体类型过滤:PHAssetMediaType.image、.video、.audio。

PhotoKit的主要类

PhotoKit包含一组用于访问、查询和更改媒体库的类。理解每一个对于有效使用框架至关重要。

PHAsset

PHAsset — 表示单个媒体内容的不可变对象。包含元数据:mediaType、mediaSubtypes、creationDate、location、pixelWidth、pixelHeight、duration(针对视频)、isFavorite、burstIdentifier。LocalIdentifier — 稳定的文本键,即使在应用程序重启后也可访问。

PHAssetCollection

PHAssetCollection — 媒体组:系统相册(Recents、Favorites、Selfies、Screenshots)、用户相册或Moments(按时间和地点自动分组)。属性:localizedTitle、assetCollectionType、assetCollectionSubtype、startDate、endDate。

PHCollectionList

PHCollectionList — 包含相册(PHAssetCollection)或其他文件夹的文件夹。很少使用,主要用于在用户界面中显示层次结构。

PHImageManager与缓存

PhotoKit不直接从PHAsset返回UIImage — 需要通过PHImageManager请求图像。这保证了图像加载时考虑了iCloud、缓存和所需大小。

组件用途特点
PHImageManager.default()用于单个请求的标准管理器请求之间无缓存
PHCachingImageManager具有预加载功能的集合管理器startCachingImages实现流畅滚动
PHImageRequestOptions请求设置:大小、模式、交付synchronous、deliveryMode、progressHandler
PHImageRequestID用于取消的请求标识符cancelImageRequest(PHImageRequestID)

PHImageManager支持三种交付模式:opportunistic(先缩小版本,然后完整版本)、highQualityFormat(仅完整质量)和fastFormat(最快的可用版本)。对于集合,始终使用PHCachingImageManager为可见单元格预加载图像。

在Swift中使用PhotoKit的示例

PhotoKit用于创建自定义画廊、编辑器和媒体处理应用程序。让我们来看三个关键场景。

从媒体库查询所有照片

PHAsset.fetchAssets结合PHFetchOptions并按创建日期排序 — 构建自定义照片库的基本查询。PHFetchResult支持懒加载和流式访问。

swift
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中用于流畅滚动。

swift
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块内执行。所有操作都被批处理并以事务方式应用。

swift
PHPhotoLibrary.shared().performChanges {
    let changeRequest = PHAssetChangeRequest(for: asset)
    changeRequest.isFavorite = .true
} completionHandler: { success, error in
    if success {
        print("已添加到收藏夹")
    }
}

通过Change Tracking进行更改和观察

PhotoKit提供通过PHPhotoLibraryChangeObserver协议观察媒体库更改的机制。在任何更改(创建、删除、编辑)时,都会调用photoLibraryDidChange方法,并传入PHChange对象。

PHChange包含每种查询类型的changeDetails:PHFetchResultChangeDetails包含removedIndexes、insertedIndexes、changedIndexes。这允许在UI中动画应用更改:针对UICollectionView执行带有move、insert、delete的performBatchUpdates。

swift
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
        }
    }
}

RAW编辑与扩展

PhotoKit通过PHContentEditingInputPHContentEditingOutput机制支持媒体编辑。应用程序请求包含原始数据的editingInput,应用更改并通过editingOutput保存结果。框架自动保留原始文件,允许用户通过重置为原始文件来撤销更改。

RAW照片(DNG、CR2、NEF)通过PHAssetResourceManager支持,它提供对原始RAW文件的访问。对于RAW处理,建议使用带有CIRAWFilter过滤器的CoreImage,该过滤器支持调整温度、曝光和锐度。PhotoKit还通过Photo Editing Extension(iOS)支持编辑器扩展 — 应用程序可以从系统编辑器调用以处理选定的照片或视频。

优化PhotoKit的使用

PhotoKit — 一个强大但资源密集型的框架。不正确的使用可能导致滚动时卡顿和内存过度消耗。遵循以下建议以获得最佳性能。

  • 为集合使用PHCachingImageManager — 为可见的 +-1 屏幕单元格预加载图像,消除滚动时的延迟
  • 设置targetSize — 切勿为缩略图请求PHImageManagerMaximumSize。使用等于单元格物理尺寸乘以屏幕比例的大小
  • 在单元格复用时取消请求 — 保存PHImageRequestID并在prepareForReuse中调用cancelImageRequest
  • 限制iCloud请求 — 快速滚动时将isNetworkAccessAllowed设置为false,仅在停止时加载iCloud照片
  • 缓存PHFetchResult — 使用相同选项重复fetchAssets会返回新的PHFetchResult。将结果保存在属性中并通过Change Observer更新

PHLivePhoto — 需要通过PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:)进行单独请求。不要为仅显示照片的单元格请求Live Photo — 使用PHLivePhotoBadge进行指示。

常见问题

什么是PhotoKit,它与AssetsLibrary有什么不同?

PhotoKit — 苹果用于处理媒体库的现代框架,在iOS 8中引入。与过时的AssetsLibrary不同,PhotoKit提供PHAsset对象模型、带有快速搜索的PHFetchResult、iCloud支持以及用于观察变化的Change Tracking。

如何通过PhotoKit请求访问媒体库?

调用PHPhotoLibrary.requestAuthorization(for: .readWrite)并在回调中处理。获得.authorized状态后,可以执行PHAsset.fetchAssets查询。写入需要.readWrite访问权限。仅读取 — .addOnly。

如何从PHAsset获取图像?

使用PHImageManager.default().requestImage并传入参数:asset、targetSize、contentMode和PHImageRequestOptions。异步方法返回PHImageRequestID,允许取消请求。对于集合,使用具有预加载功能的PHCachingImageManager。

如何跟踪媒体库中的更改?

通过PHPhotoLibrary.shared().register(self)注册观察者并实现PHPhotoLibraryChangeObserver协议。在photoLibraryDidChange方法中,您将收到带有每个fetchResult的changeDetails的PHChange,并在UI中动画应用更改。

如何在PhotoKit中处理iCloud照片?

PHImageRequestOptions中设置isNetworkAccessAllowed = true和progressHandler以跟踪从iCloud的加载。快速滚动时禁用网络访问,仅加载本地版本以避免滚动延迟。

总结

  • PhotoKit — 苹果用于处理媒体库的框架,从iOS 8和macOS 10.11起取代了AssetsLibrary。
  • PHAsset — 带有本地标识符、类型、日期、位置和大小的基本数据模型。
  • PHFetchResult 对存储执行同步查询并提供对结果的线程安全访问。
  • PHCachingImageManager 通过预加载确保集合中无延迟的流畅滚动。
  • Change Tracking 通过PHPhotoLibraryChangeObserver允许UI立即响应媒体库的变化。
  • iCloud同步 内置于框架中:图像请求会自动从iCloud加载并显示进度。
  • 优化 — 正确的targetSize、取消请求和滚动时限制iCloud对性能至关重要。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读