Skip to content

PHPickerViewController

PHPickerViewController, introduced in iOS 14, is a modern, privacy-focused replacement for UIImagePickerController for selecting photos and videos from the Photo Library. It provides a system-provided UI for media selection with enhanced user control and privacy features, ensuring apps only access explicitly selected items. This document covers the usage of PHPickerViewController in UIKit-based iOS applications.

Purpose

  • Media Selection: Allows users to select photos, videos, or live photos from the Photo Library.
  • Privacy: Limits app access to only user-selected assets, aligning with iOS privacy standards.
  • Modern UI: Offers a customizable, native interface with filtering and search capabilities.

Key Features

  • Limited Access: Apps only access media the user explicitly selects, without requiring full library permission.
  • Flexible Configuration: Supports filtering by media type, limiting selection count, and preselecting assets.
  • Delegate: Uses a delegate to handle selection results and dismissal.
  • No Camera: Unlike UIImagePickerController, it only supports Photo Library access.

Basic Usage

PHPickerViewController is presented modally, configured with a PHPickerConfiguration, and requires a delegate conforming to PHPickerViewControllerDelegate.

Example: Selecting a Single Image

swift
import UIKit
import PhotosUI

class ViewController: UIViewController, PHPickerViewControllerDelegate {
    @IBOutlet weak var imageView: UIImageView!
    
    @IBAction func pickImage(_ sender: UIButton) {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images // Only images
        configuration.selectionLimit = 1 // Single selection
        
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        present(picker, animated: true, completion: nil)
    }
    
    // Delegate method for selection
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        dismiss(animated: true, completion: nil)
        
        guard let result = results.first else { return }
        if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
            result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                DispatchQueue.main.async {
                    if let image = image as? UIImage {
                        self?.imageView.image = image
                    } else if let error = error {
                        print("Error loading image: \(error)")
                    }
                }
            }
        }
    }
}

Key Points

  • Configuration: Create a PHPickerConfiguration to specify filters, selection limits, and other options.
  • Filter: Use .images, .videos, or .livePhotos to restrict media types.
  • Selection Limit: Set selectionLimit to 1 for single selection or >1 for multiple (0 means no limit).
  • Delegate: Implement picker(_:didFinishPicking:) to handle selected results.
  • Presentation: Present modally using present(_:animated:completion:).

Advanced Features

Filtering Media

Configure the picker to show specific media types:

swift
var configuration = PHPickerConfiguration()
configuration.filter = PHPickerFilter.any(of: [.images, .videos]) // Images and videos

Multiple Selection

Allow multiple selections:

swift
configuration.selectionLimit = 3 // Allow up to 3 items

Preselected Assets

Preselect assets using asset identifiers (requires PHPhotoLibrary access):

swift
import Photos

var configuration = PHPickerConfiguration(photoLibrary: .shared())
configuration.preselectedAssetIdentifiers = ["assetID1", "assetID2"]

Handling Different Media Types

Process photos, videos, or live photos:

swift
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    dismiss(animated: true, completion: nil)
    
    for result in results {
        let provider = result.itemProvider
        if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
            provider.loadObject(ofClass: UIImage.self) { image, error in
                DispatchQueue.main.async {
                    if let image = image as? UIImage {
                        print("Loaded image")
                    }
                }
            }
        } else if provider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
            provider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
                DispatchQueue.main.async {
                    if let url = url {
                        print("Loaded video: \(url)")
                    }
                }
            }
        }
    }
}

Customizing Appearance

Set the preferred asset representation mode:

swift
configuration.preferredAssetRepresentationMode = .current // or .compatible for compatibility

iPad Popover

On iPad, configure a popover for presentation:

swift
picker.modalPresentationStyle = .popover
if let popover = picker.popoverPresentationController {
    popover.sourceView = sender
    popover.sourceRect = sender.bounds
    popover.permittedArrowDirections = .any
}

Permissions

PHPickerViewController does not require full Photo Library access, as it only provides access to user-selected assets. However, if using PHPhotoLibrary for preselected assets or other advanced features, add the NSPhotoLibraryUsageDescription key to Info.plist:

xml
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo library access to preselect assets.</string>

Request permission if needed:

swift
import Photos

PHPhotoLibrary.requestAuthorization { status in
    if status == .authorized {
        // Configure picker with PHPhotoLibrary
    }
}

Best Practices

  • Privacy: Leverage PHPickerViewController’s limited access to enhance user privacy.
  • Asynchronous Loading: Handle media loading asynchronously to avoid blocking the main thread.
  • Error Handling: Check for errors when loading media with NSItemProvider.
  • Media Types: Explicitly filter media types to match app requirements.
  • iPad Support: Configure popovers for iPad to ensure proper presentation.
  • Accessibility: Ensure the picker UI is VoiceOver-compatible.
  • Testing: Test on iPhone and iPad, with various media types and selection limits.

Limitations

  • No Camera: PHPickerViewController only supports Photo Library; use UIImagePickerController for camera access.
  • iOS 14+: Available only on iOS 14 and later.
  • Editing: Does not support in-place editing like UIImagePickerController; handle editing separately.
  • File Access: Video or large assets require file-based loading, which may involve file coordination.

Summary

PHPickerViewController is a modern, privacy-focused solution for selecting photos and videos in UIKit apps. With flexible configuration for filtering, selection limits, and media types, it provides a seamless user experience while respecting privacy. By following best practices, developers can integrate media selection efficiently and securely in iOS apps.

Released under the MIT License.