UIImagePickerController 委托未调用 Swift 3

Posted

技术标签:

【中文标题】UIImagePickerController 委托未调用 Swift 3【英文标题】:UIImagePickerController delegate not called Swift 3 【发布时间】:2016-09-25 02:50:00 【问题描述】:

表面上我认为这一定是代理问题,但在要求代理后,正确的人被退回了。

我创建了一个 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)
    

这永远不会被调用:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
    print("Image picked.") //NEVER PRINTS

【问题讨论】:

尝试设置imagePicker.delegate = selfin viewDidLoadinstead @RashwanL 是一个自定义类,但是我试着把它放在类的init 方法中,并没有什么区别。 我很困惑。 selectPhoto() 在哪里被调用? 在您的问题中发布的这个自定义类的实例是否有强烈的参考? @ClaytonAndrewCohn 你有什么解决办法吗?我在 ImageHelper 类中遇到了同样的问题。 【参考方案1】:

我不得不直接从委托中复制方法名称。由于某种原因,自动完成的方法标头错误。

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)

更新 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)

【讨论】:

你是最棒的!我很努力地想弄清楚这个问题,但并不是简单地调用了代表。原因 :: 方法名称略有不同: 我之前的内容 :: func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 什么有效: func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController. InfoKey : Any]) 不幸的是,委托是可选的,所以如果你在方法上有一个小错误,你将永远无法调试它为什么不工作。 他们似乎改变了 Swift 5 中的方法。残酷。 谢谢你,你帮助了我。他们更改了方法名称,但没有提到旧方法已被弃用,Apple 干得好。【参考方案2】:

详情

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

解决方案

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)
        
    

用法

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

完整样本

不要忘记在此处添加解决方案代码(见上图)

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)
    

【讨论】:

请不要只发布一大堆代码。一个好的答案解释了 OP 代码中的问题以及他们的答案如何解决问题。 好的。但在这个问题上,我们有很多时刻要解释。我的英语不是很完美,所以,我决定创建完整的样本。下次,我会尝试你的建议。谢谢! 另外,@VasilyBodnarchuk,我知道将委托及其方法放在我的调用视图控制器中是可行的。我想做的是创建一个辅助类来充当委托,因为我有 3-4 个不同的视图控制器需要使用完全相同的代码,而且我不想每次切换时都重复相同的两个委托调用查看控制器。 这仍然不是 UIImagePickerController/UIImagePickerDelegate 的子类。我想要做的是创建一个可以处理调用的单个子类、扩展名或文件,而不管我从哪个视图控制器调用它【参考方案3】:

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

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

class PhotoPicker: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate 

但这从未调用过委托方法。

采用 exact 相同的代码并将其放置在我调用它的 UIViewController 中使其工作。

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

【讨论】:

只需为您的视图控制器全局定义 PhotoPicker。一切都按预期工作! @IMHiteshSurani 很好的回答,它也可以工作。你能解释一下为什么在全球和本地声明会产生这样的效果 @HarshThakur 在此处添加了详细说明***.com/a/59930383/5036586【参考方案4】:

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

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

我创建了类似的课程,但是

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

对我不起作用。 在调用 'handler' 之前释放了 'picker'。

我创建了永久引用,并且成功了:

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

【讨论】:

这发生在我身上...不要将图像选择器保持为弱或函数中的实例变量...最好将其添加为属性【参考方案5】:

我也遇到了这个问题,并通过使用以下解决方案解决了这个问题。在当前完成后设置选取器的委托。

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

希望这对你有用!!

【讨论】:

【参考方案6】:

根据我的经验,这是 ARC 的问题。

如果我们将实例定义为本地实例,那么 ARC 将删除它的引用 一旦方法范围结束自动。如果您在全局范围内定义,那么它 一直保存在内存中,直到视图控制器未被取消初始化。

简答:

全局定义UIImagePickerController 实例。

长答案:

我已经创建了一次NSObjectdelegates 的公共类UIImagePickerController 的方法未被调用。

经过 5 个小时的头脑风暴,终于得到了解决方案。在从相机捕获图像期间,这似乎是与内存释放有关的问题。

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

此代码有效,(尽管它会一遍又一遍地重新显示,因为它会在 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)
    

【讨论】:

【参考方案8】:

我投了这个票,因为我错过了 UINavgationControllerDelegate 声明,而这条评论很有帮助。

imagePickerController 未被调用。

【讨论】:

【参考方案9】:

我发现对我有所帮助的是确保将代理设置为 public 而不是 private

public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])

【讨论】:

【参考方案10】:

斯威夫特 4.2

根据ViewController添加Delegate方法

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)

【讨论】:

以上是关于UIImagePickerController 委托未调用 Swift 3的主要内容,如果未能解决你的问题,请参考以下文章

UIImagePickerController、自定义 UIButton 和 AutoLayout

UIImagePickerController 实况照片

OCMock 模拟 UIImagePickerController

UIImagePickerController 图像没有改变

无法弹出 UIImagePickerController

为啥 UIImagePickerController 不能推入导航栈?