Build media selection, camera capture, photo library queries, and image caching workflows with PhotosUI (PhotosPicker), PhotoKit (PHPhotoLibrary), and AVFoundation. Targets Swift 6.3 / iOS 26+.
Contents
- Picker Selection Strategy
- Privacy and Permissions
- Image Loading and Caching
- Camera Capture Boundaries
- Route by Task
- Common Mistakes
- Review Checklist
- References
Picker Selection Strategy
| Approach | UI Framework | Permissions Needed | Use Case |
|---|---|---|---|
PhotosPicker |
SwiftUI | None (runs out-of-process) | User selects photos/videos for import |
PHPickerViewController |
UIKit | None (runs out-of-process) | UIKit equivalent of PhotosPicker |
PHPhotoLibrary |
Direct API | NSPhotoLibraryUsageDescription |
Custom gallery, background sync, asset deletion |
AVCaptureSession |
Custom UI | NSCameraUsageDescription |
Real-time camera viewfinder, photo/video capture |
Prefer PhotosPicker for standard media selection. It preserves user privacy and eliminates permission friction.
Privacy and Permissions
When accessing PHPhotoLibrary directly, request authorization and handle .limited access:
let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
switch status {
case .authorized:
// Full photo library access granted
case .limited:
// User selected specific photos (present PHPhotoLibrary.shared().presentLimitedLibraryPicker)
case .denied, .restricted:
// Direct user to Settings
case .notDetermined:
break
@unknown default:
break
}
Include NSPhotoLibraryUsageDescription (read/write) or NSPhotoLibraryAddUsageDescription (write-only save) in Info.plist.
Image Loading and Caching
Use PHCachingImageManager for fast grid thumbnail generation:
- Prepare caching: Call
startCachingImages(for:targetSize:contentMode:options:)when scrolling into view. - Reuse options: Use
PHImageRequestOptionswithdeliveryMode = .opportunisticfor quick thumbnails followed by high-res data. - Cancel obsolete requests: Cancel pending request IDs when cells scroll out of viewport.
Camera Capture Boundaries
For custom camera viewfinders using AVCaptureSession:
- Configure sessions on a dedicated serial background queue, never on
@MainActor. - Balance every transaction with
session.beginConfiguration()anddefer { session.commitConfiguration() }. - Embed viewfinders in SwiftUI using
UIViewRepresentablebacked byAVCaptureVideoPreviewLayer.
Route by Task
- For SwiftUI
PhotosPickersingle/multi-selection and media filtering recipes, read PhotosPicker Recipes. - For complete camera controllers, photo capture, video recording, and barcode scanning, read Camera Capture Patterns.
- For asset fetching, thumbnail caching with
PHCachingImageManager, and memory management, read Image Loading and Caching. For format conversion and compression, read Image Formats and Compression. - For video playback, custom player UI, and AVPlayer integration, read AV Playback Reference.
Common Mistakes
- Requesting full photo library permissions when
PhotosPickerwould suffice without any permissions. - Hardcoding
.highQualityFormatonPHImageRequestOptionsfor fast-scrolling grids, causing dropped frames. - Running
AVCaptureSession.startRunning()or configuration changes on@MainActor. - Forgetting to handle
.limitedphoto library access on iOS 14+. - Loading full-resolution
UIImageinto memory for multiple items simultaneously without downsampling.
Review Checklist
-
PhotosPickerpreferred over custom library enumeration where appropriate -
NSPhotoLibraryUsageDescriptionprovided when usingPHPhotoLibrary -
NSCameraUsageDescriptionprovided when usingAVCaptureSession -
.limitedphoto library authorization handled gracefully -
PHCachingImageManagerused with preheating for asset collections -
AVCaptureSessionconfigured and started on a serial background queue - Photo picker item loading handles cancellation and errors asynchronously
- Image assets downsampled to target display size to prevent memory spikes