Selecting photos with UIImagePickerController in Swift 5


A reusable picture picker class for iOS

So on this tutorial we’ll create a reusable class constructed on prime of UIKit in an effort to make picture choice extra nice in your apps, everyhing written in Swift 5.

This text was impressed by my earlier try to resolve the picture choosing situation in a protocol oriented approach, however that article is these days a bit of bit obsolated, plus I woundn’t use that approach anymore.

Individuals all the time study from the previous, so as a substitute of utilizing a protocol oriented strategy, this time I am going to merely go along with an ImagePicker class. No singletons, no further library, only a small helper class that may be instantiated within the acceptable place, to do it is job. 🌄

I am solely going to deal with choosing edited photos, if you would like to make use of stay photographs or motion pictures, you possibly can all the time customise the ImagePicker class, or create an summary one and implement subclasses for every media kind. I would accomplish that too. 😅

So let’s dive in, right here is my primary implementation, however you possibly can obtain a whole instance venture with video choosing as effectively from The.Swift.Dev. tutorials repository.

Privateness first!

These days privateness issues lots, so it’s important to add two necessary keys to your functions Data.plist file, in any other case you may find yourself with a horrible crash! ⚠️



Because you’d wish to get some non-public information, it’s important to present a proof message for the consumer (and for Apple) why the app is requesting digital camera & picture library entry. The NSCameraUsageDescription is for digital camera and NSPhotoLibraryUsageDescription key’s for picture library entry. Each values must be an easy string that’ll clarify the consumer why you want his/her nude photos. Pricacy is necessary! 🔒


<key>NSCameraUsageDescription</key>
<string>This app desires to take photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app desires to make use of your photographs.</string>


Clearly if you would like to make use of photographs immediately taken from the digital camera, however you do not need to entry the picture library, you simply have so as to add the right key. That is it now we’re able to do some precise coding. ⌨️



The anatomy of UIImagePickerController

The anatomy of a UIPickerController is sort of easy. Principally it is a common view controller, you simply should set a number of further properties to make it work.


let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.allowsEditing = true
pickerController.mediaTypes = ["public.image", "public.movie"]
pickerController.sourceType = .digital camera


Permits modifying is a flag that signifies if the resizing & cropping interface must be introduced after choosing & taking an image, if true you need to use the .editedImage as a substitute of the .originalImage key – contained in the picker delegate – to get the right picture from the picture information dictionary.

There are mainly two sorts of media sorts obtainable: photos and films. You will get the obtainable media kind strings for every supply kind by calling a category technique on the picker: UIImagePickerController.availableMediaTypes(for: .digital camera).

There are 3 obtainable supply sorts: .digital camera, which is the digital camera, and there are two different choices to get photos from the picture library. The .photoLibrary enum case gives you full entry, however you possibly can restrict the choice scope just for the digital camera roll if you happen to select .savedPhotosAlbum.

The delegate ought to implement each the UIImagePickerControllerDelegate and the UINavigationControllerDelegate protocols, nonetheless often my navigation controller delegate is simply an empty implementation. Should you want further navigation associated logic, you may must create a number of strategies there as effectively.

Awww, let’s simply put every thing collectively…


import UIKit

public protocol ImagePickerDelegate: class {
    func didSelect(picture: UIImage?)
}

open class ImagePicker: NSObject {

    non-public let pickerController: UIImagePickerController
    non-public weak var presentationController: UIViewController?
    non-public weak var delegate: ImagePickerDelegate?

    public init(presentationController: UIViewController, delegate: ImagePickerDelegate) {
        self.pickerController = UIImagePickerController()

        tremendous.init()

        self.presentationController = presentationController
        self.delegate = delegate

        self.pickerController.delegate = self
        self.pickerController.allowsEditing = true
        self.pickerController.mediaTypes = ["public.image"]
    }

    non-public func motion(for kind: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
        guard UIImagePickerController.isSourceTypeAvailable(kind) else {
            return nil
        }

        return UIAlertAction(title: title, fashion: .default) { [unowned self] _ in
            self.pickerController.sourceType = kind
            self.presentationController?.current(self.pickerController, animated: true)
        }
    }

    public func current(from sourceView: UIView) {

        let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        if let motion = self.motion(for: .digital camera, title: "Take picture") {
            alertController.addAction(motion)
        }
        if let motion = self.motion(for: .savedPhotosAlbum, title: "Digital camera roll") {
            alertController.addAction(motion)
        }
        if let motion = self.motion(for: .photoLibrary, title: "Picture library") {
            alertController.addAction(motion)
        }

        alertController.addAction(UIAlertAction(title: "Cancel", fashion: .cancel, handler: nil))

        if UIDevice.present.userInterfaceIdiom == .pad {
            alertController.popoverPresentationController?.sourceView = sourceView
            alertController.popoverPresentationController?.sourceRect = sourceView.bounds
            alertController.popoverPresentationController?.permittedArrowDirections = [.down, .up]
        }

        self.presentationController?.current(alertController, animated: true)
    }

    non-public func pickerController(_ controller: UIImagePickerController, didSelect picture: UIImage?) {
        controller.dismiss(animated: true, completion: nil)

        self.delegate?.didSelect(picture: picture)
    }
}

extension ImagePicker: UIImagePickerControllerDelegate {

    public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        self.pickerController(picker, didSelect: nil)
    }

    public func imagePickerController(_ picker: UIImagePickerController,
                                      didFinishPickingMediaWithInfo information: [UIImagePickerController.InfoKey: Any]) {
        guard let picture = information[.editedImage] as? UIImage else {
            return self.pickerController(picker, didSelect: nil)
        }
        self.pickerController(picker, didSelect: picture)
    }
}

extension ImagePicker: UINavigationControllerDelegate {

}


Should you needn’t choose from a supply kind, issues are fairly simple, you possibly can merely current your picker view controller, deal with every thing within the delegate and you’re carried out. Nonetheless, if you have to select from an enter supply, that includes a bit of bit extra logic, particularly on iPads. 📱

I am utilizing a UIAlertController in an effort to compose a supply kind choice dialog. I am attempting so as to add 3 actions (primarily based on the choosing supply kind), however provided that the supply kind is obtainable on that given system (eg. .digital camera just isn’t obtainable within the simulator). You possibly can verify availability by: UIImagePickerController.isSourceTypeAvailable(kind).


Alert controllers wants a number of further issues on iPads, that is why I am establishing the popoverPresentationController properties within the current technique. It is often sufficient to set the sourceView and the sourceRect properties, however you too can customise arrow instructions. ⬅️➡️⬆️⬇️

It is all the time your job to verify if the system is an iPad & set the right supply view & rect if it is wanted, in any other case your app will crash on iPads. One other factor is that it’s important to dismiss the UIPickerViewController after the picker did it is job! ⚠️

Time to say cheese! 🧀

use the picture picker class?

Properly, now you’re able to take some photos. I’ve made a easy view controller to point out you an actual fast instance. You solely want a UIImageView and a UIButton.



Now that is the code for the pattern view controller. Nothing magical, I simply move the controller as a presentationController for the ImagePicker so it’s going to be capable to current the UIImagePickerController on prime of that. I separated the delegate from the presentation controller, as a result of typically it comes helpful. 🤷‍♂️


class ViewController: UIViewController {

    @IBOutlet var imageView: UIImageView!

    var imagePicker: ImagePicker!

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.imagePicker = ImagePicker(presentationController: self, delegate: self)
    }

    @IBAction func showImagePicker(_ sender: UIButton) {
        self.imagePicker.current(from: sender)
    }
}

extension ViewController: ImagePickerDelegate {

    func didSelect(picture: UIImage?) {
        self.imageView.picture = picture
    }
}


The ImagePickerDelegate delegate on this case is the simplest one I can think about. It simply provides the picked picture so that you’re prepared to make use of it. Nonetheless in some instances you may want a number of additonal information from the picture picker.

If you wish to take this strategy one step additional, you possibly can create an summary class or a protocol that defines the fundamental performance and primarily based on which you can implement numerous media picker controllers to suit your wants. Anyway, my level right here was to replace an previous article, comply with me & subscribe for extra UIKit suggestions & tips!