PhotoKit is an Apple framework for working with the media library on iOS and macOS, providing direct access to photos, videos, and Live Photos on the device. According to Apple’s documentation, the framework replaces the legacy AssetsLibrary and supports iCloud, albums, editing, and Change Tracking. PhotoKit provides a unified API for queries, caching, and media library changes with automatic synchronization via iCloud.
Key Takeaways
PhotoKit is an Apple framework (introduced in iOS 8, macOS 10.11) that provides an object-oriented API for working with the system media library. Unlike AssetsLibrary, PhotoKit treats the media library as a database: queries return PHAsset, PHCollection, and PHCollectionList objects representing the content and storage structure.
PhotoKit supports all media types: photos (JPEG, HEIF, RAW), videos (MOV, MP4), Live Photos, and burst shots. The framework automatically manages iCloud synchronization: if an image is stored in iCloud, PhotoKit requests it over the network and reports progress via PHImageRequestOptions.progressHandler.
A key feature of PhotoKit is the data model based on PHObject with a local identifier (localIdentifier) that remains stable between sessions. This allows you to save references to media objects and restore them after app restart without re-querying.
PhotoKit is built on three levels: data model (PHObject), queries (PHFetchResult), and changes (PHPhotoLibrary.performChanges). The data model is hierarchical: PHAsset (photo/video) resides within PHAssetCollection (album), and albums are grouped into PHCollectionList (folder).
Queries are executed via PHAsset.fetchAssets and PHAssetCollection.fetchAssetCollections. All fetch methods are synchronous and return PHFetchResult, which immediately executes the query against the media library database. PHFetchResult supports fast indexed access (object(at:)) and enumeration via enumerateObjects.
PHFetchOptions is an object for configuring queries: sorting (sortDescriptors), predicate (predicate), including hidden and deleted media (includeHiddenAssets, includeAllBurstAssets). Fetch options allow filtering by media type: PHAssetMediaType.image, .video, .audio.
PhotoKit includes a set of classes for accessing, querying, and modifying the media library. Understanding each of them is essential for working effectively with the framework.
PHAsset is an immutable object representing a single media item. It contains metadata: mediaType, mediaSubtypes, creationDate, location, pixelWidth, pixelHeight, duration (for video), isFavorite, burstIdentifier. LocalIdentifier is a stable string key accessible even after app restart.
PHAssetCollection is a group of media: system albums (Recents, Favorites, Selfies, Screenshots), user albums, or Moments (automatically grouped by time and place). Attributes: localizedTitle, assetCollectionType, assetCollectionSubtype, startDate, endDate.
PHCollectionList is a folder containing albums (PHAssetCollection) or other folders. It is rarely used, mainly for displaying hierarchy in the user interface.
PhotoKit does not return UIImage directly from PHAsset — you need to request an image via PHImageManager. This ensures that the image is loaded with iCloud support, caching, and the required size.
| Component | Purpose | Feature |
|---|---|---|
| PHImageManager.default() | Standard manager for one-off requests | No caching between requests |
| PHCachingImageManager | Manager with preloading for collections | startCachingImages for smooth scrolling |
| PHImageRequestOptions | Request settings: size, mode, delivery | synchronous, deliveryMode, progressHandler |
| PHImageRequestID | Request identifier for cancellation | cancelImageRequest(PHImageRequestID) |
PHImageManager supports three delivery modes: opportunistic (first a reduced version, then full), highQualityFormat (full quality only), and fastFormat (fastest available version). For collections, always use PHCachingImageManager with image preloading for visible cells.
PhotoKit is used for creating custom galleries, editors, and media applications. Let’s look at three key scenarios.
PHAsset.fetchAssets with PHFetchOptions sorted by creation date is the basic query for building a custom photo gallery. PHFetchResult supports lazy loading and streaming access.
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("Found \(allPhotos.count) photos")
allPhotos.enumerateObjects { asset, index, stop in
print("Photo \(index): \(asset.localIdentifier)")
}
PHFetchResult is a thread-safe container. Accessing objects by index via object(at:) does not block the UI, but requesting an image via PHImageManager should be done asynchronously.
PHCachingImageManager is a subclass of PHImageManager with startCachingImages and stopCachingImages methods for preloading. It is used in UICollectionView for smooth scrolling.
let cachingManager = PHCachingImageManager()
let targetSize = CGSize(width: 200, height: 200)
// Preload for visible cells
cachingManager.startCachingImages(
for: visibleAssets,
targetSize: targetSize,
contentMode: .aspectFill,
options: nil
)
// Request image via PHImageRequestOptions with iCloud fallback
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .opportunistic
requestOptions.isNetworkAccessAllowed = .true
requestOptions.progressHandler = { progress, error, stop, info in
DispatchQueue.main.async {
print("Downloading from iCloud: \(progress * 100)%")
}
}
let requestID = cachingManager.requestImage(
for: asset,
targetSize: targetSize,
contentMode: .aspectFill,
options: requestOptions
) { image, info in
print("Got image: \(image?.size ?? .zero)")
}
Changes to the media library are performed via PHPhotoLibrary.shared().performChanges inside a changeRequest block. All operations are batched and applied transactionally.
PHPhotoLibrary.shared().performChanges {
let changeRequest = PHAssetChangeRequest(for: asset)
changeRequest.isFavorite = .true
} completionHandler: { success, error in
if success {
print("Added to favorites")
}
}
PhotoKit provides a mechanism for observing media library changes through the PHPhotoLibraryChangeObserver protocol. When any changes occur (creation, deletion, editing), the photoLibraryDidChange method is called with a PHChange object.
PHChange contains changeDetails for each query type: PHFetchResultChangeDetails with removedIndexes, insertedIndexes, changedIndexes. This allows applying changes to the UI with animation: performBatchUpdates with move, insert, delete for 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
// Apply changes to collectionView
}
}
}
PhotoKit supports media editing through the PHContentEditingInput and PHContentEditingOutput mechanism. The app requests editingInput with original data, applies changes, and saves the result via editingOutput. The framework automatically preserves the original, allowing users to revert changes by resetting to the original.
RAW photos (DNG, CR2, NEF) are supported via PHAssetResourceManager, which provides access to the original RAW file. For RAW processing, it is recommended to use CoreImage with the CIRAWFilter, which supports adjustment of temperature, exposure, and sharpness. PhotoKit also supports editor extensions via Photo Editing Extension (iOS) — an app can be invoked from the system editor to process a selected photo or video.
PhotoKit is a powerful but resource-intensive framework. Improper use can lead to scroll lag and excessive memory consumption. Follow these recommendations for optimal performance.
PHLivePhoto requires a separate request via PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:). Do not request Live Photo for cells that display only photos — use PHLivePhotoBadge for indication.
Frequently Asked Questions
PhotoKit is a modern Apple framework for working with the media library, introduced in iOS 8. Unlike the legacy AssetsLibrary, PhotoKit provides the PHAsset object model, PHFetchResult with fast search, iCloud support, and Change Tracking for observing changes.
Call PHPhotoLibrary.requestAuthorization(for: .readWrite) with a callback handler. After receiving .authorized status, you can execute PHAsset.fetchAssets queries. Write access requires .readWrite permission. For read-only — .addOnly.
Use PHImageManager.default().requestImage with parameters: asset, targetSize, contentMode, and PHImageRequestOptions. The asynchronous method returns PHImageRequestID, allowing you to cancel the request. For collections, use PHCachingImageManager with preloading.
Register an observer via PHPhotoLibrary.shared().register(self) and implement the PHPhotoLibraryChangeObserver protocol. In the photoLibraryDidChange method, receive PHChange with changeDetails for each fetchResult and apply changes to the UI with animation.
In PHImageRequestOptions, set isNetworkAccessAllowed = true and a progressHandler for tracking iCloud download progress. During fast scrolling, disable network access and load only local versions to avoid scroll delays.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also