Swift 2 initializer for conditional binding must have Optional type, not ‘UIImage’

swift2

After updating my xcode to run swift 2 it gives me these two errors which i struggle to solve.

Error 1 Cannot subscript a value of type '[String : AnyObject]?' with an index of type 'String'

Code

let image : UIImage = editingInfo[UIImagePickerControllerOriginalImage] as! UIImage

Error 2 Initializer for conditional binding must have Optional type, not 'UIImage'

Code

if let constImage = image  (Error2 display here) 
        {
            let targetWidth = UIScreen.mainScreen().scale * UIScreen.mainScreen().bounds.size.width
            let resizedImage = constImage.resize(targetWidth)

            picker.dismissViewControllerAnimated(true, completion: {
                () -> Void in

                NetworkManager.sharedInstance.postImage(resizedImage, completionHandler: {
                    (error) -> () in

                    if let constError = error
                    {
                        self.showAlert(constError.localizedDescription)
                    }
                })

            })
        }

Best Answer

Following code ...

let image : UIImage = editingInfo[UIImagePickerControllerOriginalImage] as! UIImage

... is going to crash if there's no UIImagePickerControllerOriginalImage key or if it's not an image.

From where you did get editingInfo? Because imagePickerController:didFinishPickingImage:editingInfo: is not available in Swift. You should use optional func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]).

Your second error on the following line ...

if let constImage = image

... is caused by let image: UIImage = ... line. Your image is of UIImage type, not UIImage?. Thus it's not optional and you can't use it in if let constImage = image. Must be UIImage? if you want to use it in this way. BTW there's not need to use let image: UIImage = ..., let image = ... is enough, because compiler can infer variable type from your statement.

Rewrite it to something like this.

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

  guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
    // throw an error, return from your function, whatever
    return
  }
  // from now you can use `image` safely
  // it does exist and it's not optional

  let targetWidth = UIScreen.mainScreen().scale * UIScreen.mainScreen().bounds.size.width
  let resizedImage = image.resize(targetWidth)

  picker.dismissViewControllerAnimated(true, completion: {
    () -> Void in

    NetworkManager.sharedInstance.postImage(resizedImage, completionHandler: {
      (error) -> () in

      if let constError = error
      {
        self.showAlert(constError.localizedDescription)
      }
    })

  })

}

Following part ...

  guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
    // throw an error, return from your function, whatever
    return
  }

... does this ...

  • is there a value in info dictionary for UIImagePickerControllerOriginalImage key? if no, else {} statement is executed,
  • value is there, can I cast it to UIImage? if no, else {} statement is executed,
  • now we have value from info successfully casted to UIImage and stored in image, else {} statement is not executed and our function continues.

Safe way how to get a value from dictionary of some type when dictionary value type is AnyObject for example.

Related Topic