web-dev-qa-db-fra.com

Délégué UIImagePickerController non appelé Swift 3

En apparence, j’ai pensé que c’était un problème de délégué, mais après avoir demandé au délégué, le droit était renvoyé.

J'ai créé une classe ImagePicker pour gérer tout le matériel UIImagePickerController. Tout fonctionne jusqu'à ce que les méthodes déléguées doivent être appelées. Une fois que j'ai choisi une photo, imagePicker est rejeté, mais la méthode didFinishPickingMediaWithInfo n'est jamais appelée. S'il vous plaît aider! Merci :)

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)
    }
}

Cela ne s'appelle jamais:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    print("Image picked.") //NEVER PRINTS
}
8
Clayton Andrew Cohn

Détails

Xcode 9.2, Swift 4

Solution

extension BaseViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

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

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        NSLog("\(info)")
        let image = info[UIImagePickerControllerOriginalImage] as? UIImage
        imagePickerController(picker, pickedImage: image)
    }

    @objc func imagePickerController(_ picker: UIImagePickerController, pickedImage: UIImage?) {
    }
}

Échantillon complet

BaseViewController.Swift

import UIKit

class BaseViewController: UIViewController {

    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()
        imagePicker.delegate = self
    }
}
extension BaseViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

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

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        NSLog("\(info)")
        let image = info[UIImagePickerControllerOriginalImage] as? UIImage
        imagePickerController(picker, pickedImage: image)
    }

    @objc func imagePickerController(_ picker: UIImagePickerController, pickedImage: UIImage?) {
    }
}

ViewController.Swift

import UIKit

class ViewController: BaseViewController {

    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) {
        imagePicker.allowsEditing = false
        imagePicker.sourceType = .photoLibrary

        present(imagePicker, animated: true, completion: nil)
    }

    override func imagePickerController(_ picker: UIImagePickerController, pickedImage: UIImage?) {
        if let image = pickedImage {
            imageView?.image = image
            dismiss(animated: true, completion: nil)
        }
    }
}
9
Vasily Bodnarchuk

Je devais copier les noms de méthodes directement du délégué. Pour une raison quelconque, l'auto-complétion présente des en-têtes de méthode incorrects.

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)
}
5
Dustin Spengler

Vous devez vous assurer que UIImagePickerController n'a pas été publié avant que le délégué appelle.

J'ai créé une classe ImagePicker pour gérer tous les fichiers UIImagePickerController.

J'ai créé une classe similaire, mais

func onButtonDidTap(sender: UIButton) {
.....
    let picker = VLImagePickerController()
    picker.show(fromSender: sender, handler: { (image: UIImage?) -> (Void) in
        if (image != nil) {
            self.setImage(image!)
        }
    })
....
}

n'a pas fonctionné pour moi . 'picker' a été publié avant que 'handler' puisse être appelé.

J'ai créé une référence permanente, et cela a fonctionné:

let picker = VLImagePickerController()

    func onButtonDidTap(sender: UIButton) {
    .....
            //let picker = VLImagePickerController()
            picker.show(fromSender: sender, handler: { (image: UIImage?) -> (Void) in
                if (image != nil) {
                    self.setImage(image!)
                }
            })
    ....
        }
2
Victor_Z

J'ai également fait face à ce problème et résolu en utilisant la solution ci-dessous. Définir le délégué du préparateur après la fin du présent.

controller.present(picker, animated: true, completion: {
            self.picker.delegate = self
        })

J'espère que cela fonctionnera pour vous !!

2
iDev750

J'ai trouvé que le code de délégué devait être dans un UIViewController actif.

Au départ, j'avais essayé de placer mon code dans un fichier séparé, tel que NSObject avec les protocoles de délégation corrects déclarés, comme ceci:

class PhotoPicker: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

Mais cela n'a jamais appelé les méthodes de délégué.

Prendre le même code exact et le placer dans UIViewController dont je l’appelais l’a fait fonctionner.

Il semble que la meilleure solution consiste à créer une vue de type contextuelle et à laisser son ViewController conserver le code.

1
Nico teWinkel

Ce code fonctionne (bien qu'il réapparaisse encore et encore car il affiche le sélecteur dans viewWillAppear, ceci est juste pour garder le code petit) Je regarderais ce qui est différent de cela. Cela pourrait avoir à voir avec votre contrôleur de vue supérieure? Pourquoi ne pas simplement afficher le sélecteur à partir d'un contrôleur de vue plutôt que d'accéder au contrôleur de vue supérieur de l'application? En outre, une fois que vous avez reçu le rappel du délégué, vous devez fermer le contrôleur de vue.

import UIKit
import MobileCoreServices

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()
        imagePicker.mediaTypes = [kUTTypeImage as String]
        imagePicker.delegate = self
    }

    override func viewDidAppear(_ animated: Bool) { // keeps reopening, do not this in your code. 
        present(imagePicker, animated: true, completion: nil)
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        imagePicker.dismiss(animated: true, completion: nil)
    }
}
0
possen