uiimagepickercontrollerdelegate不叫Swift 3

时间:2023-02-12 15:01:49

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

我创建了一个ImagePicker类来处理所有UIImagePickerController的东西。在需要调用委托方法之前,所有东西都可以工作。在我选了一张照片后,imagePicker就会消失,但是didFinishPickingMediaWithInfo方法永远不会被调用。请帮助!谢谢:)

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
}

5 个解决方案

#1


9  

Details

Xcode 9.2, Swift 4

Xcode 9.2,斯威夫特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?) {
    }
}

Full sample

BaseViewController.swift

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

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

#2


4  

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

#3


2  

Yo have to make sure that UIImagePickerController was not released before delegate called.

你必须确保UIImagePickerController在委托调用之前没有被释放。

I created an ImagePicker class to handle all the UIImagePickerController stuff.

我创建了一个ImagePicker类来处理所有UIImagePickerController的东西。

I created similar class, but

我创建了类似的类,但是

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

did not work for me. 'picker' was released before 'handler' could be called.

我没有工作。在调用“handler”之前,“picker”被释放。

I created permanent reference, and it worked:

我创建了永久性参考,它奏效了:

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

#4


0  

This code works, (although, it redisplays over and over because it displays the picker in viewWillAppear, this is just to keep code small). I would look at what is different from this. It could have to do with your top view controller? Why not just display the picker from a view controller rather than go to application's top view controller? Also, once you get the delegate callback, you need to dismiss the view controller.

这段代码可以工作(尽管它反复地显示,因为它在viewWillAppear中显示了选择器,这只是为了使代码更小)。我想看看和这个有什么不同。它可能和你的顶部视图控制器有关?为什么不从视图控制器中显示选择器,而不是到应用程序的*视图控制器中呢?另外,一旦获得委托回调,就需要取消视图控制器。

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

#5


0  

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

我发现委托代码必须在一个活动的UIViewController中。

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

我最初尝试将代码放在一个单独的文件中,如NSObject,并声明了正确的委托协议,如下所示:

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.

使用完全相同的代码并把它放在我调用的UIViewController中使它工作。

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

看起来最好的解决方案是创建一个弹出式视图,并让它的ViewController保存代码。

#1


9  

Details

Xcode 9.2, Swift 4

Xcode 9.2,斯威夫特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?) {
    }
}

Full sample

BaseViewController.swift

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

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

#2


4  

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

#3


2  

Yo have to make sure that UIImagePickerController was not released before delegate called.

你必须确保UIImagePickerController在委托调用之前没有被释放。

I created an ImagePicker class to handle all the UIImagePickerController stuff.

我创建了一个ImagePicker类来处理所有UIImagePickerController的东西。

I created similar class, but

我创建了类似的类,但是

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

did not work for me. 'picker' was released before 'handler' could be called.

我没有工作。在调用“handler”之前,“picker”被释放。

I created permanent reference, and it worked:

我创建了永久性参考,它奏效了:

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

#4


0  

This code works, (although, it redisplays over and over because it displays the picker in viewWillAppear, this is just to keep code small). I would look at what is different from this. It could have to do with your top view controller? Why not just display the picker from a view controller rather than go to application's top view controller? Also, once you get the delegate callback, you need to dismiss the view controller.

这段代码可以工作(尽管它反复地显示,因为它在viewWillAppear中显示了选择器,这只是为了使代码更小)。我想看看和这个有什么不同。它可能和你的顶部视图控制器有关?为什么不从视图控制器中显示选择器,而不是到应用程序的*视图控制器中呢?另外,一旦获得委托回调,就需要取消视图控制器。

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

#5


0  

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

我发现委托代码必须在一个活动的UIViewController中。

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

我最初尝试将代码放在一个单独的文件中,如NSObject,并声明了正确的委托协议,如下所示:

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.

使用完全相同的代码并把它放在我调用的UIViewController中使它工作。

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

看起来最好的解决方案是创建一个弹出式视图,并让它的ViewController保存代码。