66

I'm using Apple's Swift iOS Tutorial. Which is throwing an error,

Cannot subscript a value of type '[String : Any]' with an index of type 'UIImagePickerController.InfoKey'

The function they defined is below.

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

    // The info dictionary may contain multiple representations of the image. You want to use the original.
    guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
    }

    // Set photoImageView to display the selected image.
    photoImageView.image = selectedImage

    // Dismiss the picker.
    dismiss(animated: true, completion: nil)
}

I'm using Xcode Version 10.0 beta 3, which includes Swift 4.2.

I'd like to understand how to traverse the docs to understand what might have changed or broken.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
drobati
  • 761
  • 1
  • 5
  • 4
  • I noticed that another line later in this tutorial also threw an error - `button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchUpInside)`. In case others have the same issue -- I was able to fix it by adding `@objcMembers` right at the beginning of the class line, like this: `@objcMembers class RatingControl: UIStackView {`. See https://www.hackingwithswift.com/example-code/language/how-to-fix-argument-of-selector-refers-to-instance-method-that-is-not-exposed-to-objective-c – Keara Jun 05 '19 at 19:29

8 Answers8

118

The signature of the method has changed in Swift 4.2

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

and you have to write

guard let selectedImage = info[.originalImage] as? UIImage else {
    fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}

You can figure out such terminology changes yourself by reading the documentation or by commenting out the entire method, retype the first few characters and use code completion.

vadian
  • 274,689
  • 30
  • 353
  • 361
27

I'm following also the same tutorial, the updated code looks like this:

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

    // The info dictionary may contain multiple representations of the image. You want to use the original.
    guard let selectedImage = info[.originalImage] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
    }

    // Set photoImageView to display the selected image.
    photoImageView.image = selectedImage

    // Dismiss the picker.
    dismiss(animated: true, completion: nil)
}
edymerchk
  • 1,203
  • 13
  • 19
20

Swift 5

In latest version of swift 4 or 5 the delegate method is given below, it should work

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // Code here
}

And use,

guard let selectedImage = info[.editedImage] as? UIImage else {

}



func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    guard let selectedImage = info[.editedImage] as? UIImage else {

    }
}
Saranjith
  • 11,242
  • 5
  • 69
  • 122
9

Use like this,

guard let selectedImage = info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
8

In Swift 4 and 5 like so:

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

    guard let selectedImage = info[.editedImage] as? UIImage else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
    }

    self.myImageView.image = selectedImage

    picker.dismiss(animated: true, completion: nil)
}
Mr T
  • 1,409
  • 1
  • 17
  • 24
3

I am also following the tutorial. It is working after changing as below.

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

    // The info dictionary may contain multiple representations of the image. You want to use the original.
    guard let selectedImage = info[.originalImage] as? UIImage
        else {
        fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
    }

    // Set photoImageView to display the selected image.
    photoImageView.image = selectedImage

    // Dismiss the picker.
    dismiss(animated: true, completion: nil)
}

I am using XCode 11 and Swift 5.

Saju KS
  • 71
  • 5
1

Method has been changed a little bit in Swift 4.2.

First initialise these two variables:

var imagePicker = UIImagePickerController()
var pickedImageProduct = UIImage()

extension yourViewController: UIImagePickerControllerDelegate,UINavigationControllerDelegate{
//create an IBAction to access Camera
    @IBAction func accessCameraBtn(_ sender: UIButton) {
        imagePicker.delegate = self
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        self.present(imagePicker, animated: true, completion: nil)
    }
//create an IBAction to access Gallery
    @IBAction func accessGalleryBtn(_ sender: UIButton) {
        imagePicker.delegate = self
        imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
        self.present(imagePicker, animated: true, completion: nil)
    }
//Final step put this Delegate    
    func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        guard let selectedImage = info[.originalImage] as? UIImage else {
           Print("Error: \(info)")
        }

            pickedImageProduct = selectedImage

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

        dismiss(animated: true, completion: nil)
    }

}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Akbar Khan
  • 2,215
  • 19
  • 27
1

In Swift 4.2 you can write the function as:

    func photoLib()
    {
        //opens Photo Library, call the function in a @IBAction func
        let myPickerController = UIImagePickerController()
        myPickerController.delegate = self;
        myPickerController.sourceType = 
        UIImagePickerController.SourceType.photoLibrary
        myPickerController.allowsEditing = true
        present(myPickerController, animated: true)
    }


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

    guard let image = info[.editedImage] as? UIImage else {
        print("No image found")
        photoLabel.text = "Photo Not Found"
        return
    }
}