Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImagePickerController delegate not called Swift 3

On the surface I thought that this had to be a delegate issue, but after asking for the delegate the right one was returned.

I created an ImagePicker class to handle all the UIImagePickerController stuff. Every thing works until the delegate methods need to be called. After I pick a photo, the imagePicker dismisses, but the didFinishPickingMediaWithInfo method never gets called. Please help! Thanks :)

func selectPhoto() {
    imagePicker.delegate = self //Delegate gets set here

    let photoAsk = UIAlertController.init( //Ask user if they want to take picture or choose one
        title: "Edit Profile Picture",
        message: nil,
        preferredStyle: .alert)
    let cameraAction = UIAlertAction.init(
        title: "Take Photo",
        style: .default) { (UIAlertAction) in
            if (UIImagePickerController.isSourceTypeAvailable(.camera)) {
                self.imagePicker.sourceType = .camera
                UIApplication.topViewController()!.present(self.imagePicker, animated: true, completion:nil)
            } else {
                print("Cannot access camera in simulator.")
                return
            }
    }
    let photoLibraryAction = UIAlertAction.init(
        title: "Photo Library",
        style: .default) { (UIAlertAction) in
            self.imagePicker.sourceType = .photoLibrary
            UIApplication.topViewController()!.present(self.imagePicker, animated: true, completion:nil)
            print("UIImagePickerDelegate: \(self.imagePicker.delegate.debugDescription)") // <--THIS PRINTS OUT "AppName.ImagePicker: 0x145d7bdf0>", and the class name is ImagePicker
    }
    let cancelAction = UIAlertAction.init(
        title: "Cancel",
        style: .cancel) { (UIAlertAction) in return }

    photoAsk.addAction(cameraAction)
    photoAsk.addAction(photoLibraryAction)
    photoAsk.addAction(cancelAction)

    imagePicker.mediaTypes = [kUTTypeImage as String]

    UIApplication.topViewController()?.present(photoAsk, animated: true, completion: nil)
    }
}

This never gets called:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    print("Image picked.") //NEVER PRINTS
}
like image 340
Clayton C. Avatar asked Sep 25 '16 02:09

Clayton C.


4 Answers

swift 4.2

Add Delegate method according ViewController

UIImagePickerControllerDelegate,UINavigationControllerDelegate

//IBOutlet
@IBOutlet weak var ImagePhoto: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
}

//Button Action Take Photo
@IBAction func btnPhotoTap(_ sender: Any) {
   
           let imagePicker = UIImagePickerController()
           imagePicker.delegate = self
           imagePicker.sourceType = .photoLibrary // Or .camera as you require
           imagePicker.allowsEditing = true
           self.present(imagePicker, animated: true, completion: nil)
}

//MARK:-imagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
           let image1 =  info[UIImagePickerController.InfoKey.editedImage] as? UIImage
           self.ImagePhoto.image = image1
           self.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
   
           print("Cancel")
           self.dismiss(animated: true, completion: nil)
}
like image 131
Pravin Parmar Avatar answered Sep 16 '22 16:09

Pravin Parmar


I had to copy the method names straight from the delegate. For some reason the auto-complete has the method headers wrong.

public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
        //save image
        //display image
    }
    self.dismiss(animated: true, completion: nil)
}

public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    self.dismiss(animated: true, completion: nil)
}

UPDATE SWIFT 5:

public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
        //save image
        //display image
    }
    self.dismiss(animated: true, completion: nil)
}
like image 21
Dustin Spengler Avatar answered Nov 15 '22 15:11

Dustin Spengler


Details

  • Xcode 9.2, Swift 4
  • Xcode 10.2.1 (10E1001), Swift 5

Solution

extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        dismiss(animated: true, completion: nil)
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        print("\(info)")
        if let image = info[.originalImage] as? UIImage {
            imageView?.image = image
            dismiss(animated: true, completion: nil)
        }
    }
}

Usage

let imagePickerController = UIImagePickerController()
imagePickerController.allowsEditing = false
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)

Full sample

Do not forget to add the solution code here (look above)

import UIKit

class ViewController: UIViewController {

    private weak var imageView: UIImageView?

    override func viewDidLoad() {
        super.viewDidLoad()
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)
        stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        stackView.addArrangedSubview(imageView)
        imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
        imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
        self.imageView = imageView

        let button = UIButton(frame: .zero)
        button.setTitle("Button", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(showImages), for: .touchUpInside)
        stackView.addArrangedSubview(button)
    }

    @IBAction func showImages(_ sender: AnyObject) {
        let imagePickerController = UIImagePickerController()
        imagePickerController.allowsEditing = false
        imagePickerController.sourceType = .photoLibrary
        imagePickerController.delegate = self
        present(imagePickerController, animated: true, completion: nil)
    }
}
like image 16
Vasily Bodnarchuk Avatar answered Nov 15 '22 15:11

Vasily Bodnarchuk


I found that the delegate code had to be within an active UIViewController.

I originally tried to have my code in a separate file, as as NSObject with the correct delegate protocols declared, like this:

class PhotoPicker: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

But that never called the delegate methods.

Taking the exact same code and placing it within the UIViewController I was calling it from made it work.

It looks like the best solution is to create a pop-up type view, and have its ViewController keep the code.

like image 5
Nico teWinkel Avatar answered Nov 15 '22 17:11

Nico teWinkel