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保存代码。