This time we will take a look on how to take photos and browse them on iOS.
Using UIImagePickerController
Creating user interface for taking photos consists of presenting an instance of UIImagePickerController. Controller needs a delegate and source type what defines if we are going to take a photo or pick a photo from the library. But even before creating the controller it is required to call isSourceTypeAvailable(_:)
class method and verifying if the source type is available. For example, it returns false if picker’s sourceType is set to UIImagePickerController.SourceType.photoLibrary
and the library is empty. Makes sense, as there are no photos to pick from.
@IBAction func takePhoto(_ sender: Any) { | |
openPhotoPicker(withSource: .camera) | |
} | |
@IBAction func choosePhoto(_ sender: Any) { | |
openPhotoPicker(withSource: .photoLibrary) | |
} | |
@discardableResult private func openPhotoPicker(withSource source: UIImagePickerController.SourceType) -> Bool { | |
guard UIImagePickerController.isSourceTypeAvailable(source) else { return false } | |
let picker: UIImagePickerController = { | |
let picker = UIImagePickerController() | |
picker.delegate = self | |
picker.sourceType = source | |
return picker | |
}() | |
present(picker, animated: true, completion:nil) | |
return true | |
} |
UIImagePickerControllerDelegate contains two methods we need to implement for handling interactions in image picker. Firstly, consuming taken or picked images and secondly, dismissing the picker. Info dictionary in imagePickerController(_:didFinishPickingMediaWithInfo:)
contains quite a many values from images to metadata. All the possible keys can be seen here. As a bare minimum we need to handle editedImage
and originalImage
keys. If it is required to add the image to photo library, then this can be done by calling UIImageWriteToSavedPhotosAlbum()
. This starts an asynchronous operation for adding the image to library. And if needed, it is possible to specify callback when this operation finishes.
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { | |
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { | |
let handleImage: (UIImage?) -> () = { (image) in | |
self.imageView.image = image | |
self.imageView.isHidden = (image == nil) | |
if let image = image { | |
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) | |
} | |
} | |
if let image = info[.editedImage] as? UIImage { | |
handleImage(image) | |
} | |
else if let image = info[.originalImage] as? UIImage { | |
handleImage(image) | |
} | |
else { | |
handleImage(nil) | |
} | |
dismiss(animated: true, completion: nil) | |
} | |
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { | |
dismiss(animated: true, completion: nil) | |
} | |
} |
Privacy statements
Before going ahead and presenting the image picker it is required to add privacy statements to info.plist
. Privacy - Camera Usage Description (NSCameraUsageDescription)
is required for using the camera and Privacy - Photo Library Additions Usage Description (NSPhotoLibraryUsageDescription)
when using UIImageWriteToSavedPhotosAlbum()
for storing photos. Values of those keys are localised descriptions which are shown when app requests to use the camera or when adding the photo to the library.
Summary
Setting up user interface for taking photos is quite easy thanks to UIImagePickerController. All in all it was a three step process: configure picker, add privacy statements and handle images.
Sample app
PhotoTaker (GitHub) Xcode 10, Swift 4.2
References
UIImagePickerControllerDelegate (Apple)
NSCameraUsageDescription
NSPhotoLibraryUsageDescription