Kreason Naidoo
Kreason Naidoo

Reputation: 1181

PhotoPicker discovery error: Error Domain=PlugInKit Code=13

I'm trying to display an image from the photo library in a UIImageView

The full error is:

2017-06-09 21:55:59.063307+0200 firstapp2.0[12873:1120778] PhotoPicker discovery error: Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}

My code is included below:

import UIKit

class ViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate{

    @IBOutlet weak var pic: UIImageView!
    @IBOutlet weak var text: UILabel!

    var chosenImage : UIImage!

    override func viewDidLoad() {
        super.viewDidLoad()        
        pic.isUserInteractionEnabled = true;
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [AnyHashable: Any]) {
        var chosenImage = info[UIImagePickerControllerEditedImage]
        self.pic!.image = chosenImage as! UIImage
        picker.dismiss(animated: true, completion: nil)
    }

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

    @IBAction func tap(_ sender: Any) {        
        self.text.text = "Kreason"
        let imagePicker = UIImagePickerController()    
        imagePicker.delegate = self        
        imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
        imagePicker.allowsEditing = false    
        self.present(imagePicker, animated: true, completion: nil)
    }
}

Upvotes: 118

Views: 74097

Answers (30)

Benpaper
Benpaper

Reputation: 144

In my case as swift allocation memory management seems to be optimised and fixed by Apple Team. My code was perfectly working till a swift update and I found my "mistake" was that I wasn't retaining the picker but It has been working for ages without the retention so here a full ready to work solution.

// Add Privacy - Photo Library Usage Description to your info.plist
<key>NSPhotoLibraryUsageDescription</key>
<string>APPNAME need to access your pictures to violate your privacy :P</string>

And

import Photos    
class MyImageSelector: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {

    var picker = UIImagePickerController() 
    // Make sure to retain this picker var until the picker returned

    func checkPermission() {
        let call = self.presentAuthorized

            let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
            switch photoAuthorizationStatus {
            case .authorized:
                print("Access is granted by user")
                showPicker()
            case .notDetermined:
                PHPhotoLibrary.requestAuthorization({ newStatus in
                print("status is \(newStatus)")
                if newStatus == PHAuthorizationStatus.authorized {
                    /* do stuff here */
                    print("success")
                    showPicker()
                }
                })
            case .restricted:
                print("User do not have access to photo album.")
            case .denied:
                print("User has denied the permission.")
            }

    }

    func showPicker() {
        picker = UIImagePickerController()
        picker.allowsEditing = true
        picker.sourceType = .photoLibrary
        picker.delegate = self  //Don't forget this line!
        self.present(picker, animated: true, completion: nil)
    }

    @objc public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        // DO something with picture
    }

    @objc public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // User cancelled the pick
    }
}

Upvotes: 1

zvjerka24
zvjerka24

Reputation: 1792

Try not to make UIImagePickerController inside method but to make it as a class variable and to create it only once.

I had the same issue as you when I forgot to set a delegate to UIImagePickerController

Upvotes: 0

Xab Ion
Xab Ion

Reputation: 1319

Swift 5 and Above:

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var pic: UIImageView!
    @IBOutlet weak var text: UILabel!

    var chosenImage : UIImage!

    override func viewDidLoad() {
        super.viewDidLoad()
        pic.isUserInteractionEnabled = true
    }



func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let image = info[.editedImage] as? UIImage else { return }
        dismiss(animated: true)
        chosenImage = image
        **pic.image = chosenImage**

    }

    @IBAction func tap(_ sender: Any) {
        self.text.text = "Kreason"
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        //imagePicker.dataSource = self
        imagePicker.allowsEditing = false
        self.present(imagePicker, animated: true)

    }
}

Upvotes: 0

Braden Holt
Braden Holt

Reputation: 1594

This "Error Domain=PlugInKit Code=13" error has confounded a lot of people even though it seems to be a harmless apple debug message. I was having trouble getting the image I picked to set in my UI and thought that that error was the problem however it was something a bit more subtle.

I have my image picker controller in a file separate from the view controller that's presenting it.

MyViewController.swift

class MyViewController: UIViewController {
    @IBOutlet weak var profileImage: UIImageView!

    ...
}

extension MyViewController: ImagePickerDelegate {
    func didSelect(image: UIImage?) {
        self.profileImage.image = image
    }
}

ImagePicker.swift

open class ImagePicker: NSObject {
    ...
    private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
        controller.dismiss(animated: true, completion: {self.delegate?.didSelect(image: image)}
        )
    }
}

Most of the tutorials and answers have the completion set to nil. However if you set the completion to nil and call the delegate's didSelect method separately, the method gets called but the image doesn't set so make sure to use dismiss' completion.

And again, I know this answer might not be directly related to the original question but I have a feeling a lot of people are coming here for this issue and the given solutions aren't helping. The reason is that most of the people giving answers have their image picker controller in the same class as their main view controller and thus not needing to use a completion.

Upvotes: 2

Martin De Simone
Martin De Simone

Reputation: 2148

Use didFinishPickingMediaWithInfo

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        self.dismiss(animated: true, completion: nil)
        var chosenImage = info[UIImagePickerController.InfoKey.editedImage] as! UIImage
        userProfileImage.image = chosenImage

        uploadImage(chosenImage)
}

Upvotes: 0

user2153553
user2153553

Reputation: 405

This fixes the issue in Swift 4:

Change the code below

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {}

to this:

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


Swift 4.2 update:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){}

Upvotes: 6

Dharmesh Kheni
Dharmesh Kheni

Reputation: 71852

Fixed it by setting 1 second delay when setting image.

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

    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {

        picker.dismiss(animated: false, completion: nil)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
            self.discussionImage.image = image
        })
    }
}

Upvotes: 4

Apfelsaft
Apfelsaft

Reputation: 5846

Finding the fix for this problem took me forever. It looks like the problem is that the function imagePickerController of the UIImagePickerControllerDelegate cannot be found. If you have set the delegate correctly and it stopped working after upgrading to Swift 4, the problem is probably that you didn't make it accessible to Objective-C by using @objc which is required since Swift 4.

It has to be:

@objc func imagePickerController(...

instead of

func imagePickerController(...

Upvotes: 4

Marcos Reboucas
Marcos Reboucas

Reputation: 3489

Had this same issue on Swift 4.2 and Xcode 10.0. Although the image picker was working correctly Xcode showed this error on console. To get rid of this:

  • On Xcode menu Product > Scheme > Edit Scheme
  • Select 'Run' tab, then 'Arguments'
  • On 'Environment Variables' section add a variable with Name OS_ACTIVITY_MODE and Value disable

Upvotes: 0

jaskiratjd
jaskiratjd

Reputation: 797

use this code

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])

Upvotes: 2

FRIDDAY
FRIDDAY

Reputation: 4179

XCODE 10.1 / SWIFT 4.2 :

  1. Add required permissions (others mentioned)

  2. Implement this delegate func:

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    
        if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            self.imgView.contentMode = .scaleAspectFit
            self.imgView.image = pickedImage
        }
    
        dismiss(animated: true, completion: nil)
    }
    

Upvotes: 11

logan.Nguyen
logan.Nguyen

Reputation: 219

I fixed this issue, call function below into viewdidload or viewWillAppear or viewDidAppear to check permission for your app.

func checkPermission() {
        let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        switch photoAuthorizationStatus {
        case .authorized:
            print("Access is granted by user")
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization({
                (newStatus) in
                print("status is \(newStatus)")
                if newStatus ==  PHAuthorizationStatus.authorized {
                    /* do stuff here */
                    print("success")
                }
            })
            print("It is not determined until now")
        case .restricted:
            // same same
            print("User do not have access to photo album.")
        case .denied:
            // same same
            print("User has denied the permission.")
        }
    }

And to use the above method, do not forget to add import Photos at top of the class.

Upvotes: 11

Mario Vasile
Mario Vasile

Reputation: 96

I got the same message when I was trying to present another controller from the picker callback imagePickerController. The solution which worked for me was to move my code inside the completion callback from the the picker dismiss method

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        picker.dismiss(animated: true) {
            if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
                let cropController:CropViewController = CropViewController(croppingStyle: .circular, image: pickedImage)
                cropController.delegate = self
                self.present(cropController, animated: true, completion: nil)
            }
        }
    }

Upvotes: 7

danner.tech
danner.tech

Reputation: 109

The solution that worked for me was simply going into Product (at the top of the screen) -> Scheme -> EditScheme -> Arguments

In Environment Variables, add OS_ACTIVITY_MODE with a value of "disable"

Hopefully this works for someone else!

I'll attach a screenshot just in case my description seemed confusingenter image description here

Upvotes: -3

Jason Rybka
Jason Rybka

Reputation: 175

In my case I was getting this error because I was presenting an image picker controller without first verifying if the user had allowed access to images. Elsewhere in my code the user had granted permission so I think all I needed to do was import Photos. However, since they 'may' not have granted permission at that point in the app adding this just before I presented the image picker controller solved the issue for me (import Photos as well).

// request photos permission if permission has not been granted
    if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
        PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) in

        })
    }

If this answer seems redundant my apologies but I had to piece together from a few different answer to get my solution working. Perhaps this will help someone else using Swift 4.

Upvotes: 2

Aleem
Aleem

Reputation: 3291

On my end UINavigationControllerDelegate delegate is missing.

class YourViewController:UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate

Upvotes: 1

EGibson
EGibson

Reputation: 477

This had me stumped, but the answer at the link below worked for me. Error is gone and image displays as expected

Like one of the answers above, you have to have (_ picker... but also @objc before the function.

@objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
...
}

https://forums.developer.apple.com/thread/82105

Upvotes: 3

Ryan
Ryan

Reputation: 552

Make sure you are subclassing both: UIImagePickerControllerDelegate, UINavigationControllerDelegate.

Also, remember to set the delegate:

let picker = UIImagePickerController()
picker.allowsEditing = true
picker.sourceType = .photoLibrary
picker.delegate = self  //Don't forget this line!
self.present(picker, animated: true, completion: nil)

Credits to this source.

Upvotes: 4

FreitDev
FreitDev

Reputation: 33

This is what I did and it solved my issue.

  • add @objc
  • add internal
  • add _ before imagePicker
  • make sure you are using Any and not AnyObject

Hope this helps!

Upvotes: 2

Changnam Hong
Changnam Hong

Reputation: 1679

If you have not done so, try this.

Product > Scheme > Edit Scheme > Environment Variables OS_ACTIVITY_MODE: disable

It solves my issue.

Upvotes: 7

G Reynolds-Titko
G Reynolds-Titko

Reputation: 151

Tried a few of the combination responses without much success.

Using Swift 4, I found that I needed to make sure the following two items were implemented to ensure that the image was selected and placed into the picker (note that the "[discovery] errors encountered while discovering extensions:

Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}"

message still displays in the console, but it does not prevent you from adding an image). Maybe this is a message that results in the picker being dismissed?

1) The delegate for the UIImagePickerController is (UIImagePickerControllerDelegate & UINavigationControllerDelegate)? so need to explicitly add the UINavigationControllerDelegate as one of the protocols:

class ViewController:UIViewController, UIImagePickerControllerDelegate, 
    UINavigationControllerDelegate { .... }. 

2) Make sure that the info.plist has the Privacy - Photo library Usage Description key and String value set.

Of course, you need to ensure that you create a UIImagePickerController and set its delegate equal to self in ViewDidLoad():

class ViewController:UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 
    let imagePickerController = UIImagePickerController()
    override func viewDidLoad() {
        super.viewDidLoad()
        imagePickerController.delegate = self
    }
    ...
}

Upvotes: 15

xuzepei
xuzepei

Reputation: 1219

Please check by steps as follow:

  1. Import Photos
  2. Has access to album:

    func authorizeToAlbum(completion:@escaping (Bool)->Void) {
    
    if PHPhotoLibrary.authorizationStatus() != .authorized {
        NSLog("Will request authorization")
        PHPhotoLibrary.requestAuthorization({ (status) in
            if status == .authorized {
                DispatchQueue.main.async(execute: {
                    completion(true)
                })
            } else {
                DispatchQueue.main.async(execute: {
                    completion(false)
                })
            }
        })
    
    } else {
        DispatchQueue.main.async(execute: {
            completion(true)
        })
    }
    }
    
  3. Present UIImagePickerController

    self.authorizeToAlbum { (authorized) in
        if authorized == true {
            let picker = UIImagePickerController()
            picker.delegate = self
            picker.allowsEditing = false
            picker.sourceType = .photoLibrary
    
            self.present(picker, animated: true, completion: nil)
        }
    }
    
  4. The key step, make sure the delegate method is like following strictly

    // MARK: - UIImagePickerControllerDelegate Methods
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
        self.pickedImage = pickedImage
        if let finalImage = handleImage(originalImage: self.pickedImage!, maskImage: self.maskImage!) {
            self.imageView.image = finalImage
        }
    }
    
    dismiss(animated: true, completion: nil)
    }
    

Upvotes: 2

Daniel Arantes Loverde
Daniel Arantes Loverde

Reputation: 2314

* Missing DELEGATE * in Swift 3

In my case, all settings was correct:
1 - Delegates ( UIImagePickerControllerDelegate,UINavigationControllerDelegate );
2 - Permissions already verified;
3 - Plist already done;
4 - Everything read on this Answers, i did;

But i forgot to implement pickerview.delegate = self on viewDidLoad Because i COPY and PASTE from my other viewController and forget that!

I hope it help somebody, review your COPY / PASTE first!!!

Upvotes: 10

roshan posakya
roshan posakya

Reputation: 1030

click on imageView to load image from photo library and show preview on same imageview. on swift 4

 let imagePicker = UIImagePickerController()
        @IBOutlet weak var userImage: UIImageView! 

     override func viewDidLoad() {
                super.viewDidLoad()
                 imagePicker.delegate = self
                let tap = UITapGestureRecognizer(target: self, action: #selector(SignUpViewController.click))
                userImage.addGestureRecognizer(tap)
                userImage.isUserInteractionEnabled = true
            }

            @objc func click()
            {
                imagePicker.allowsEditing = false
                imagePicker.sourceType = .photoLibrary
                present(imagePicker, animated: true, completion: nil)
            }


            @objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
                if  let chosenImage = info[UIImagePickerControllerOriginalImage] as? UIImage{
                userImage.contentMode = .scaleAspectFit
                userImage.image = chosenImage
                }
                dismiss(animated: true, completion: nil)
            }

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

Upvotes: 0

Levi Lais
Levi Lais

Reputation: 351

This might not be the most directly helpful answer - but hopefully it will help! I'm 99% sure that this particular error message isn't actually pointing you to the real problem. I spent hours pulling my hair out over this same exact issue.

1) I had authorization for photos printing to the console when I'd launch my picker, 2) I could navigate and pick a photo easy enough, and 3) when I would return me to my view upon dismissing the picker, my button image wasn't updated with the new photo... and the only hint that I had to the problem was the exact same error message that you are receiving.

Turns out I was hard-coding a placeholder image in ViewWillAppear instead of ViewDidLoad. Every time the picker was dismissing, it was calling ViewWillAppear and replacing my chosen image with my hard coded image. I fixed that issue and sure enough - everything is working fine now... and I'm still seeing that error message every time I return from the picker.

I recommend looking somewhere other than the ImagePicker for your problem and you'll likely find it.

Upvotes: 9

user3159598
user3159598

Reputation: 223

I found this solution. We got this error due to these two reason which is mentioned below.

  1. First we need to call this method in for authorization

Authorization Code

func checkPermission() {
  let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus() switch photoAuthorizationStatus {
    case .authorized: print("Access is granted by user")
    case .notDetermined: PHPhotoLibrary.requestAuthorization({
      (newStatus) in print("status is \(newStatus)") if newStatus == PHAuthorizationStatus.authorized { / do stuff here */ print("success") }
    })
    case .restricted: / print("User do not have access to photo album.")
    case .denied: / print("User has denied the permission.")
  }
}
  1. Correct way of method Calling of didFinishPickingMediaWithInfo

Wrong:

private func imagePickerController( picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
} 

Right

@objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
} 

I hope this solution will help you out to resolve this error.

If it works for you don't forget to mark it's as a correct, so this will help to other to find the correct way.

Upvotes: 18

Muhammad Hamid
Muhammad Hamid

Reputation: 1

i found the solution of IMage PickerView.....

@IBOutlet weak var myImageView: UIImageView!

var imagePicker = UIImagePickerController()


  @IBAction func selectImage(_ sender: Any) {

        let myPickerController = UIImagePickerController()
        myPickerController.delegate = self;
        myPickerController.sourceType = UIImagePickerControllerSourceType.photoLibrary

        self.present(myPickerController, animated: true, completion: nil)

    }

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

        var selectedImageFromPicker: UIImage?

        if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage
        {
            selectedImageFromPicker = editedImage as! UIImage


        }else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage{

            selectedImageFromPicker = originalImage as! UIImage


        }

        dismiss(animated: true, completion: nil)

        if var selectedImage = selectedImageFromPicker
        {
            myImageView.image = selectedImage
        }

    }

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

Upvotes: 0

iOS Developer
iOS Developer

Reputation: 85

This solved my error :

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
    addPhotoBtn.setImage(pickedImage, for: .normal)
    dismiss(animated: true, completion: nil)


}

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

}

Upvotes: 2

melson.jao
melson.jao

Reputation: 204

I have the same error and I fixed it in this way:

get image object in different way depends on UIImagePickerController allowsEditing is true or false

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

    if isImagePickerAllowEditing {
        sourceImage = info[UIImagePickerControllerEditedImage] as? UIImage
    } else {
        sourceImage = info[UIImagePickerControllerOriginalImage] as? UIImage
    }

    ....

}

And of course, ask the permission to access photo library first as above comments.

Upvotes: 1

I read the all these answers and little bit modified here and not needed to dismiss, this worked for me, Thanks others who have replied here.

    @objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

      print("########### media picked")
      picker.dismiss(animated: true, completion: nil)
      let img = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
      //set img -picked image to "profileImage" UIimageView
      //use image here
       self.profileImage.image = img
       }
    }

Upvotes: 0

Related Questions