Cannot subscript a value of type '[String : Any]' with an index of type 'UIImagePickerController.InfoKey'
IosSwiftUiimagepickercontrollerIos Problem Overview
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.
Ios Solutions
Solution 1 - Ios
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.
Solution 2 - Ios
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)
}
Solution 3 - Ios
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 {
}
}
Solution 4 - Ios
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)")
}
Solution 5 - Ios
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)
}
Solution 6 - Ios
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.
Solution 7 - Ios
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)
}
}
Solution 8 - Ios
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
}
}