How to let user select photos from iOS Photo Library
Much better experience. No permissions required and multi-select!
Published: June 25, 2020 Sponsored App StoreIn iOS 14 there is a brand new way to let users select a photo(s) or video(s) from their library to use in your app and it has some cool features and benefits. Let's see what these are and how basic PHPickerViewController
usage looks like.
Benefits
No permissions required - you don't need to provide usage description in Info.plist
to present the new picker and system does not show the allow access dialog. That is because users have full control over what media they select and subsequently send to your app.
Modern UI consistent with Photos - the new picker is much easier to use because the UI is very similar to what you get in Photos and there is also a search. This should be much better selection experience for the users than with the UIImagePickerViewController
Multi-selection - what else to say? 🙂
Usage overview
Using the new PHPickerViewController
is pretty straightforward. It uses the traditional delegate model that will alert you when user finishes her selection. There is just a single delegate method to support and a bit of configuration.
Start by importing the PhotosUI
framework:
import PhotosUI
Then continue with creating the configuration object PHPickerConfiguration
. So far this allows to customize how many media files user can select and what kind of:
var configuration = PHPickerConfiguration()
configuration.selectionLimit = 3
configuration.filter = .images
In this example we are setting the selectionLimit
to 3 (default is 1). You can also set 0
to mean unlimited. And next with filter
we are saying that we want just images.
You can also ask for videos
or livePhotos
and combine these with the any(of:
method like so:
configuration.filter = .any(of: [.livePhotos, .images])
Next create the picker itself and set yourself as its delegate
:
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
We have two things left. Present the picker:
present(picker, animated: true, completion: nil)
The UI is different depending if multi-selection is enabled or not.
And implement the delegate:
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true, completion: nil)
guard !results.isEmpty else { return }
}
}
So far we are just dismissing the picker and checking that we have results.
Unlike with UIImagePickerViewController
we won't get the URL path to the file but instead a NSItemProvider
that we can ask to load a specific object. For images this may look like this:
We will use a loop and get the itemProvider
for each result:
for result in results {
let provider = result.itemProvider
}
And then we can load the UIImage
.
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { (image, error) in
DispatchQueue.main.async {
if let image = image as? UIImage {
self.imageView.image = image
}
}
}
}
Just to be safe we first ask if the object can be loaded and then load it. To be honest I am not that well versed with NSItemProvider
.
And to recap. Here is entire code from above:
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true, completion: nil)
guard !results.isEmpty else { return }
}
for result in results {
let provider = result.itemProvider
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { (image, error) in
DispatchQueue.main.async {
if let image = image as? UIImage {
self.imageView.image = image
}
}
}
}
}
}
With UIImagePickerViewController
there was a settings to specify the resolution for exported media which here does not appear to be a case. I plan to investigate this further and either update this post or write new one detailing how to get video or image with specific resolution.
EDIT: Indeed there is no support for automatic compression. The picker will always pass the original video/image and it is up to the app to do the necessary compressions or edits.
In the WWDC 2020 session about this new photo picker Apple specifically mentions that we should be using this new one instead of the older UIImagePickerViewController
. This is not deprecated yet but presets for image/video quality are as per new documentation:
Uses: Xcode 12 & Swift 5.3