PhotoKit: Build Powerful iOS Photo Experiences Faster—
PhotoKit is Apple’s high-level framework for working with the Photos library on iOS, macOS, and tvOS. It provides a modern, efficient, and privacy-aware API for accessing, editing, and managing the user’s photos and videos. Using PhotoKit, developers can build rich photo experiences—browsers, editors, collage makers, filters, and more—while respecting system performance and the user’s privacy. This article explains PhotoKit’s core concepts, common workflows, best practices, performance tips, and practical examples to help you ship robust photo features faster.
Why use PhotoKit?
- Unified access to the user’s Photos library, including assets (images and videos), collections (albums, moments), and metadata.
- Non-blocking, thread-safe APIs that operate asynchronously and integrate with Grand Central Dispatch (GCD) and modern Swift concurrency.
- Change tracking via the PHPhotoLibraryChangeObserver protocol, enabling apps to react to external modifications.
- Editing support through content editing input/output and adjustment data, allowing non-destructive edits and integration with system Photos app.
- Performance optimizations such as requestOptions, imageManager caching, and efficient asset resource access.
- Privacy-first design: explicit user permission, limited access options (e.g., selected photos), and tight sandboxing.
Core PhotoKit concepts
- PHAsset — represents an image or video in the Photos library. Contains metadata like creationDate, mediaType, pixelWidth/Height, duration (for video), and location.
- PHAssetCollection — a grouping of assets (albums, moments, smart albums).
- PHFetchResult — returned by fetch APIs; a collection-like container of assets or collections. It is lazy and optimized for large libraries.
- PHImageManager — primary API for requesting image and video data in various sizes and quality. Offers PHCachingImageManager for prefetching.
- PHPhotoLibrary — entry point for write operations, change observer registration, and performing changes via performChanges or performChangesAndWait.
- PHAssetChangeRequest / PHAssetCollectionChangeRequest — objects used within change blocks to create, delete, or modify assets and collections.
- PHContentEditingInput / PHContentEditingOutput — used by editors to fetch full-quality image data and save adjustment data non-destructively.
- PHLivePhoto / PHLivePhotoRequestOptions — support for Live Photos (image + short video).
- PHAssetResourceManager — lower-level access to asset resources (useful for cloud assets, HEIC/HEIF/HEVC formats, and direct file-level access).
Typical workflows
1) Requesting permission
Always check and request access before attempting to fetch assets.
- Full library access:
PHPhotoLibrary.requestAuthorization { status in // handle PHAuthorizationStatus.authorized / limited / denied / notDetermined }
With iOS 14+ you may handle limited library access and prompt the user to expand selection with PHPhotoLibrary.shared().presentLimitedLibraryPicker(from:)
from a view controller.
2) Fetching assets and collections
Use PHFetchOptions to filter and sort.
let options = PHFetchOptions() options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] options.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.image.rawValue) let results = PHAsset.fetchAssets(with: options)
PHFetchResult behaves like an immutable collection; access items by indexing or enumerate.
3) Requesting images
Use PHImageManager to obtain thumbnails, screen-size, or full-size images. Supply targetSize, contentMode, and options.
let imageManager = PHImageManager.default() let requestOptions = PHImageRequestOptions() requestOptions.isNetworkAccessAllowed = true requestOptions.deliveryMode = .highQualityFormat imageManager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions) { image, info in // image may be low-res first, then high-res; check info dictionary }
For full-resolution or original data, use requestImageDataAndOrientation
or requestImageData(for:options:resultHandler:)
(APIs vary by iOS version).
4) Editing assets non-destructively
Fetch a PHContentEditingInput, perform edits, and write a PHContentEditingOutput with adjustmentData so edits are reversible.
asset.requestContentEditingInput(with: options) { (input, info) in guard let input = input else { return } // load full-size image at input.fullSizeImageURL or input.displaySizeImage // create PHContentEditingOutput with input let output = PHContentEditingOutput(contentEditingInput: input) // write edited image to output.renderedContentURL // set output.adjustmentData = PHAdjustmentData(formatIdentifier: "com.example.editor", formatVersion: "1.0", data: myData) PHPhotoLibrary.shared().performChanges { let request = PHAssetChangeRequest(for: asset) request.contentEditingOutput = output } completionHandler: { success, error in // handle result } }
5) Saving new photos/videos
Create assets by adding resources to a change request.
PHPhotoLibrary.shared().performChanges { let creationRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: imageURL) // or use creationRequest.addResource(with: .photo, data: Data, options: nil) } completionHandler: { success, error in }
6) Observing changes
Register as a PHPhotoLibraryChangeObserver to get change notifications and update UI accordingly.
PHPhotoLibrary.shared().register(self) // implement photoLibraryDidChange(_ changeInstance: PHChange)
Best practices
- Always run heavy work off the main thread. PhotoKit’s fetches and image requests are asynchronous but follow-up processing (e.g., decoding large images) should be backgrounded.
- Use PHCachingImageManager to prefetch images for collection views to keep scrolling smooth.
- Respect network access options: allow background downloading (iCloud) only when appropriate and provide UI indicators for downloading progress.
- For editors, prefer non-destructive edits using adjustmentData so users can revert or re-edit later.
- Handle limited library authorization gracefully: detect selected assets and guide users to expand access only if necessary.
- Avoid repeatedly requesting full-resolution assets; cache results when possible and reuse images or file URLs.
- Prefer using asset resources (PHAssetResource) when you need original files (HEIC, etc.) or need to preserve exact file formats and metadata.
Performance tips
- Use the correct targetSize for requestImage; requesting much larger images than display size wastes memory and CPU. Use UIScreen scale factor for crispness.
- Use deliveryMode .opportunistic for thumbnails (shows available low-res first), and .highQualityFormat for single final image.
- Batch change operations inside a single performChanges block when updating multiple assets.
- Employ PHCachingImageManager’s startCachingImages and stopCachingImages near collection view visible rect changes.
- Use requestID cancellation if a cell is reused before an image request completes to avoid unnecessary work.
Handling videos and Live Photos
- Use requestAVAsset(forVideo:options:resultHandler:) or requestPlayerItem(forVideo:options:resultHandler:) to obtain playable assets.
- For Live Photos, use PHLivePhoto.request(with:targetSize:contentMode:options:resultHandler:). Provide PHLivePhotoRequestOptions to control network access and delivery of paired resources.
- When exporting or sharing, prefer AVAssetExportSession for video encoding and PHAssetResourceManager to write original resource files if you need exact originals.
Example: Basic photo browser (structure)
- Permissions manager — request and handle authorization state.
- Data source — fetch PHAssets with PHFetchOptions and maintain a PHFetchResult reference.
- Image caching — PHCachingImageManager tied to collection view prefetching.
- Cell — start image request in prepareForReuse cancellation, show placeholder, manage progress for iCloud images.
- Detail view — request high-quality image or full-size resource, and allow edit/share/delete via change requests.
- Change observer — update fetch results/UI on external library changes.
Common pitfalls and how to avoid them
- Forgetting to check PHPhotoLibrary authorization status, leading to crashes or empty UI. Always fail gracefully and show instructions.
- Holding onto large UIImages in memory — prefer on-disk caching or re-requesting with appropriate sizes.
- Not handling iCloud Photo Library assets: requests may return placeholder info and require network access; handle the info dictionary keys (e.g., PHImageResultIsInCloudKey).
- Blocking the main thread when writing large files in performChangesAndWait — use the async performChanges and handle UI state.
Advanced uses
- Custom editors: implement PHContentEditingController to integrate with system Photos app and support non-destructive edits.
- Direct resource access: PHAssetResourceManager.requestData(for:options:dataReceivedHandler:completionHandler:) for streaming resource bytes (useful for uploads).
- Smart albums and moments: leverage PHCollectionList and localized collections for richer browsing experiences.
- Metadata manipulation: use Image I/O or AVFoundation together with asset resources to read/write EXIF, orientation, and location (note: limited writing of metadata in-place may require creating new assets).
Sample checklist before shipping
- [ ] Handle and test all authorization states, including limited access.
- [ ] Implement caching for smooth scrolling.
- [ ] Provide UI for iCloud downloads and errors.
- [ ] Ensure non-destructive editing or clearly document destructive behavior.
- [ ] Test on devices with large libraries, slow networks, and different storage conditions.
- [ ] Localize strings related to Photos permissions and explanatory messages.
PhotoKit is a robust, well-designed framework that, when used correctly, removes much of the complexity of interacting with the Photos library. By understanding its core objects, choosing the right image request options, respecting user privacy, and applying caching and background processing, you can build performant, user-friendly photo experiences quickly.
If you want, I can: convert the code snippets to Swift concurrency (async/await), provide a complete sample app structure, or write a tutorial on non-destructive editing with PhotoKit. Which would you prefer?
Leave a Reply