UIImagePickerController delegate not called Swift

2020-08-13 15:42发布

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
}

9条回答
闹够了就滚
2楼-- · 2020-08-13 15:54

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)
}
查看更多
手持菜刀,她持情操
3楼-- · 2020-08-13 16:00

I voted this one up because I was missing the UINavgationControllerDelegate declaration and this comment helped.

imagePickerController wasn't being called.

查看更多
冷血范
4楼-- · 2020-08-13 16:01

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.

查看更多
Lonely孤独者°
5楼-- · 2020-08-13 16:07

swift 4.2 Add according ViewController

 UIImagePickerControllerDelegate,UINavigationControllerDelegate 
   @IBOutlet weak var ImagePhoto: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @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)
 }
查看更多
Anthone
6楼-- · 2020-08-13 16:09

As per my experience, it is an issue of ARC.

If we define instance as locally then ARC will remove its reference automatically once methods scope end. If you define globally then it is kept in memory until the view controller is not deinitialized.

Short Answer:

Define UIImagePickerController instance globally.

Long Answer:

I have created once the common class of NSObject and delegates method of UIImagePickerController is not called.

After 5 hours of brainstorming, Finally, get the solution. It seems like an issue related to memory deallocation during the captured image from the camera.

public typealias CameraBlock = (UIImage?, Bool) -> Void

class HSCameraSingleton: NSObject {
    
    var pickerController = UIImagePickerController()
    private var completionBlock: CameraBlock!
    var presentationController: UIViewController?
    
    public init(presentationController: UIViewController) {
        super.init()
        self.presentationController = presentationController
    }
    
    
    public func present(completionBlock: @escaping CameraBlock) {
        guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
            return
        }
        
        self.pickerController = UIImagePickerController()
        self.pickerController.delegate = self
        self.pickerController.allowsEditing = true
        self.pickerController.sourceType = .camera
        self.completionBlock = completionBlock
        self.presentationController?.present(self.pickerController, animated: true, completion: nil)
    }
}


extension HSCameraSingleton: UIImagePickerControllerDelegate,UINavigationControllerDelegate {
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        self.completionBlock?(nil,false)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let image = info[.originalImage] as? UIImage else {
            self.completionBlock?(nil,false)
            return
        }
        self.completionBlock?(image,true)
        pickerController.dismiss(animated:true, completion: nil)
    }
}


class AuthViewController: UIViewController{

lazy var overlay = HSCameraSingleton(presentationController:self)

@IBAction func actionLoginTap(_ sender: UIControl) {
        
        overlay.present { (image, status) in
            print(image,status)
        }
    }
}
查看更多
时光不老,我们不散
7楼-- · 2020-08-13 16:12

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)
    }
}
查看更多
登录 后发表回答