I am trying to set the image property on a UIImageView. When I use a UIImage to set the .image property it throws this error every time:
"unexpectedly found nil while unwrapping an Optional value"
The problem is that my UIImage is not nil.
Here is the code where I am setting the UIImage
func setPhotosForNewsItem(photoArray:[Photo]) {
println("Image Count: " + String(photoArray.count))
var image:UIImage = photoArray[0].photo
println(image.description)
self.newsImage.image = image
}
Here is the console output:
Image Count: 2
UIImage: 0x7fdd93c5cdd0, {1115, 1115}
fatal error:
unexpectedly found nil while unwrapping an Optional value (lldb)
I am able to use the Quick Look tool in xCode on my supposedly nil UIImage and see the photo that I am trying to use. Why would I be throwing a nil error when my UIImage is clearly not nil?
UPDATE::
It seems that I am not properly storing the UIImage in my array. Here is where I download my images and store them to my array for unpacking later.
var relatedPhotos:[PFObject] = relations as! [PFObject]
//println(relations!)
var photoArray:[Photo] = [Photo]()
for photo in relatedPhotos {
var newPhoto = Photo()
var photoFile:PFFile = photo.objectForKey("photo") as! PFFile
newPhoto.object = photo
newPhoto.objectID = photo.objectId!
photoFile.getDataInBackgroundWithBlock({(imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
newPhoto.photo = UIImage(data:imageData!)!
//println(newPhoto.photo)
photoArray.append(newPhoto)
if photoArray.count == relatedPhotos.count {
if newObject is FieldReport {
var report = newObject as! FieldReport
report.photos = photoArray
updatedReports.append(report)
//println("Report Count 1: " + String(updatedReports.count))
}
else {
var report = newObject as! Feature
report.photos = photoArray
updatedReports.append(report)
}
if updatedReports.count == objects.count {
self.delegate?.fieldReports(updatedReports)
}
}
}
})
}
I know that this works to download and display the photo as I have just used it successfully to do so. To me that means I am not storing the UIImage properly. Is there a different way I should be storing these image files?
You can prevent the crash from happening by safely unwrapping
func setPhotosForNewsItem(photoArray:[Photo]) {
println("Image Count: " + String(photoArray.count))
if var image:UIImage = photoArray[0].photo
{
println(image.description)
self.newsImage.image = image
}
}
Setup breakpoint and check what's wrong
EDIT:
The only thing i can purpose - check what happens here:
newPhoto.photo = UIImage(data:imageData!)!
seems like it's the main reason of all problems. check type of imageData, try to convert it to image via, for example UIImage(CGImage: <#CGImage!#>). You need to figure out how to deal with this image.
Related
I am using Tesseract OCR in my app. For gallery images it's working fine if I use a very clear image such as this one
5 text image
But for some images it gives me an error and the app crashes in my iPhone. App almost always crashes when I use a camera image as well. Now I want to know how to handle FATAL Error in Swift 2.2 . How can I show an alert that image was unreadable instead of crashing my app. I tried do {} catch {} but it doesn't work.
func checkWithOCR() throws{
let ocrSample = myImageView.image //image picker from gallery
//FATAL ERROR ON THIS LINE.
tesseract.image = ocrSample!.fixOrientation().g8_blackAndWhite()
if(tesseract.recognize()){
let recognizedText = tesseract.recognizedText
if recognizedText != nil{
print("recognizedText: \(recognizedText)")
let trimmedText = String(recognizedText.characters.filter { !" \n\t\r,".characters.contains($0) })
myImageView.image = tesseract.image
convertCurrency(Float(trimmedText)!) //convert the tesseract text
}
}
SwiftSpinner.hide()
}
HERE IS THE ERROR:
recognizedText:
fatal error: unexpectedly found nil while unwrapping an Optional value
I know why this error occurs as there was no value on the line I mentioned above. How can I show an alert box if this error occurs instead of a crash.
P.S: I tried if ( ocrSample!.fixOrientation().g8_blackAndWhite() != nil ) {}
It doesn't work
The image on a UIImageView is an UIImage optional, meaning that it can have a value (contain an image) or it can be nil.
So, when you're saying:
let ocrSample = myImageView.image
your ocrSample is now an UIImage optional, which you then have to unwrap before you use it.
When you then say:
tesseract.image = ocrSample!.fixOrientation().g8_blackAndWhite()
you are force unwrapping your ocrSample by using !, meaning that you are telling the compiler to just unwrap and use the optional, regardless of it being nil or not. This causes a crash when you then try to use that unwrapped optional if it contains nil.
What you can do is unwrap ocrSample using an if let like so:
func checkWithOCR() throws{
if let ocrSample = myImageView.image {
tesseract.image = ocrSample.fixOrientation().g8_blackAndWhite()
if(tesseract.recognize()){
let recognizedText = tesseract.recognizedText
if recognizedText != nil{
print("recognizedText: \(recognizedText)")
let trimmedText = String(recognizedText.characters.filter { !" \n\t\r,".characters.contains($0) })
myImageView.image = tesseract.image
convertCurrency(Float(trimmedText)!) //convert the tesseract text
}
}
SwiftSpinner.hide()
} else {
//No value could be found, do your error handling here
}
}
Here:
if let ocrSample = myImageView.image
you are trying to unwrap the value of myImageView.image into ocrSample, if that succeeds, then you know for sure that ocrSample is not nil and can use it onwards. If it fails, then you can do your error handling, show an alert view and whatever else you need to do.
Hope that helps you.
I have faced a problem with setting uiimageview from other viewcontroller.
DiaryDetailController.swift
let imageViewPageController = (segue.destinationViewController as! ImageViewPageController)
if (imageCount > 0) {
imageViewPageController.image1 = tempImage1
}
ImageViewPageController.swift
let page: ImageViewDetailController! = storyboard?.instantiateViewControllerWithIdentifier("imageViewDetailController") as! ImageViewDetailController
page.setImage(image1)
pages.append(page)
ImageViewDetailController.swift
func setImage(image: UIImage) {
imageView.image = image
}
And I got following error on "imageView.image = image".
fatal error: unexpectedly found nil while unwrapping an Optional value
How should I solve this problem?
You're probably trying to set the image before the IBOutlets are set.
Create a UIImage property in ImageViewDetailController (let's call it image), and instead of saying:
page.setImage(image1)
You can do this
page.image = image1
Then let the ImageViewDetailController deal with it once it has loaded. So in the viewDidLoad, just say
imageView.image = self.image
I have an array that starts out empty but is filled with PFFiles (image data) with a PFQuery. A UIImageView has its image set using the data in the PFFile Array. However, if the array is empty then there is an error saying array index is out of range. Therefore, I need something testing to see if array is empty and I can't find a way to do that.
var imageFiles = [PFFile]()
And then in the viewDidLoad
self.imageFiles[self.imageCounter].getDataInBackgroundWithBlock{
(imageData, error) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
self.mainPic.image = image
}else {
}
}
I would like to be able do something like:
If let testVariable = self.imageFiles[self.imageCounter] as PFFile {
}
Or more simply:
If self.imagesFiles[self.imageCounter] == nil {
}
But neither of those work
The problem is you're going out of the bounds of the array, as you said. You can void this by checking the size of the array before trying to access an element. The following should do the trick:
if (self.imagesFiles.count > self.imageCounter) {
//myImage = self.imageFiles[self.imageCounter];
}
I'm successfully pulling in data from Parse into swift, but my images don't seem to be working the way I'm doing it.
In my cellForRowAtIndexPath method, I do the following:
var event: AnyObject? = eventContainerArray[indexPath.row]
if let unwrappedEvent: AnyObject = event {
let eventTitle = unwrappedEvent["title"] as? String
let eventDate = unwrappedEvent["date"] as? String
let eventDescription = unwrappedEvent["description"] as String
let eventImage = unwrappedEvent["image"] as? UIImage
println(eventImage)
if (eventImage != nil){
cell.loadItem(date: eventDate!, title: eventTitle!, description: eventDescription, image: eventImage!)}
else {
let testImage: UIImage = UIImage(named: "test-image.png")!
cell.loadItem(date: eventDate!, title: eventTitle!, description: eventDescription, image: testImage )
}
}
}
return cell
}
I'm using println() with my PFQuery, and I am seeing this as part of the object that's loading in: image = "<PFFile: 0x7fee62420b00>";
So I'm getting title, date, description, etc. all loading fine as part of the above eventContainerArray, but when I look at eventImage, it's nil every time. In the code above, it always defaults to loading test-image.png, being that the image is coming up nil. Am I simply handling that PFFile the improper way? Not sure why it's not working.
Thanks!
Your image is likely a PFFile object. You will need to load it to get an UIImage object from it.
let userImageFile = unwrappedEvent["image"] as PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
let eventImage = UIImage(data:imageData)
// do something with image here
}
}
I'm not familiar with Parse, but given what you're seeing from the println() it looks like what you've received isn't a UIImage but instead some sort of data type. This makes sense; you aren't going to be receiving ObjC objects over the network. So you are getting a file, but when you use the conditional downcast (x as? UIImage) it's returning nil because you don't have a UIImage.
Instead you're going to need to cast to PFFile, and then probably create a UIImage with UIImage(data: file.getData) or something similar. I'm not familiar with exactly how Parse works.
Edit: here's a related question that might be helpful: I can't get image from PFFile
var image = self.imageData[index] as NSString
if let derp = image as NSString? {
println(" \(image)")
} else {
println("is nil")
}
dataViewController.dataImage.image = UIImage(named: image) as UIImage
That last line:
dataViewController.dataImage.image = UIImage(named: image) as UIImage
gives me "Can't unwrap Optional.None", despite the image object successfully passing the optional binding test as shown here https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_428 . The image string does print at the bottom of Xcode.
It is possible you are getting that error because an image with that name does not exist. However, you also have some issues with your optional binding.
Optional binding is different from casting. You don't provide a new type. Also, even if casting was the way to do it, you are casting to an optional, which doesn't prove that image is not nil.
You have already asserted to the compiler that image is not nil with your as NSString on the first line. If this conversion is not successful at runtime, your whole app will crash.
After binding an optional, you should use the local variable, not use the optional later
This means your code should look like this:
var possibleImageName = self.imageData[index] as? NSString
if let imageName = possibleImageName {
var possibleImage : UIImage? = UIImage(named: imageName)
if let image = possibleImage {
dataViewController.dataImage.image = image
}
} else {
println("is nil")
}
After you understand the optional binding process, and the difference from casting, you can shorten the code to this:
if let imageName = self.imageData[index] as? NSString {
if let image = UIImage(named: imageName) as UIImage? {
dataViewController.dataImage.image = image
}
} else {
println("is nil")
}
Note: The check for nil from initializers is strange. You have to cast it to be an optional type so that you can actually test it because initializers from Objective-C actually return Implicitly Unwrapped Optionals.
UIImage(named:) may return nil in case the image with given name cannot be found. You need to check it did not nil.
var img : UIImage? = UIImage(named: image)
if img != nil {
dataViewController.dataImage.image = img!
}
or
if let img = UIImage(named: image) as UIImage! {
dataViewController.dataImage.image = img
}