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
}
Related
I'd like to use 'if let' here but I can't get it to work. Can someone help me?
guard animal?.img != nil else {
print ("image is nil")
return
}
let animalImage = UIImage(data: animal!.img!) as UIImage?
saveImageView.image = animalImage
I think you mean "guard let". BTW, you almost always want to avoid force unwrapping.
Also since UIImageView.image is optional you don't need to check the returned value from UIImage constructor
guard let data = animal?.img else {
print ("image data is nil")
return
}
saveImageView.image = UIImage(data: data)
There are several things you can do with an optional value:
var optionalText:String?
...
var text4:String? = optionalText // assign it to another optional variable
var text5 = optionalText // the same, the compiler will infer that text5 is also an optional string
optionalText?.append(" hello") // will only call `append(_:)` on `text` if it's not nil, otherwise this will be ignored
let text6:String = optionalText ?? "It was nil!" // use the coalescing operator
let text7:String = optionalText! // force-unwrap it into a String; if it's nil, your app will crash
// you CANNOT, however, treat it as a non-optional:
let newText = "Hello " + optionalText // this won't compile
// you can unwrap it:
if let text8 = optionalText {
// this code block will ONLY execute if textField.text was not nil
let newString = "Hello "+ text8 // this constant will only work in this block
// in that case, text8 will be of type String (non-optional)
// so it shouldn't be treated as an optional
}
let newString = "Hello "+ text8 // this won't compile
// unwrap it with `guard`:
guard let text8 = optionalText else {
// this code block will ONLY execute if textField.text WAS nil
// and it must return
return
}
let newString = "Hello "+ text8 // this is okay, text8 lives on in case of `guard`
These are the differences between guard let and if let:
if let nonOptional = optional {} will assign a value to a non-optional constant by unwrapping an optional value and execute the code block, but only if the optional isn't nil. The non-optional constant will only live inside the if let { } block. Use this if you want to handle both cases (nil or otherwise) and then move on with your code.
guard let nonOptional = optional else { } will do the same assignment if possible, but code flow will be different afterwards: it will execute the else block in case the optional value is nil, and that else block will have to quit the scope (return, continue, or break); it must not fall through, i.e. execution must not continue right after the block (the compiler will make sure of that). However, your nonOptional constant will live on after this statement. Use this if your code largely depends on the optional value not being a nil: quit early if the condition fails, and otherwise hold on to the non-optional value and use if for the rest of your enclosing scope.
Btw., you can also use var instead of let if it makes sense, in both cases.
The main purpose of guard is to avoid the "pyramid of doom" type of nested checks:
// pyramid of doom
func doomed() {
if condition1 {
if condition2 {
if condition3 {
// success scenario
print("all good")
// ...
} else {
print("failed condition 3")
return
}
} else {
print("failed condition 2")
return
}
} else {
print("failed condition 1")
return
}
}
// avoiding pyramid of doom
func nonDoomed() {
guard condition1 else {
print("failed condition 1")
return
}
guard condition2 else {
print("failed condition 2")
return
}
guard condition3 else {
print("failed condition 3")
return
}
// success scenario
print("all good")
// ...
}
Without guard, your success scenario is hidden in the middle of nested if statements related to error conditions, making your code difficult to read or edit.
With guard, each error condition is handled separately, and after you get them out of the way, you can go on with the success scenario. With guard let, you can also ensure that all the necessary constants and variables are available for the rest of the scope.
What you seem to need is one of two things:
Optionally unwrap and use your optional:
if let realImage = animal?.img {
let animalImage = UIImage(data: animal!.img!) as UIImage?
saveImageView.image = animalImage
}
// otherwise, saveImageView.image will not be assigned a new value
Simply pass an optional value
saveImageView.image = animal?.img
This should work because the left-hand side and the right-hand side are both UIImage? optionals.
This should do it, you assign your image data to first variable, then use it to assign to the second one:
if let img = animal?.img, let animalImage = UIImage(data: img) {
//do something
}
Probably don't need as? Data and as? UIImage, it depends on your model.
You can do it like below...
if let imgName = animal?.img {
saveImageView.image = UIImage(data: imgName)
}
I would extend Data and create an image property to return an optional image from your data object:
extension Data {
var image: UIImage? { UIImage(data: self) }
}
Usage:
saveImageView.image = animal?.img?.image
This would allow you to provide a default image as well in case of nil using the nil coalescing operator:
saveImageView.image = animal?.img?.image ?? UIImage(named: "defaultImage")
guard let and if let are effectively the same thing. In fact, if you are guarding the first statement to check if it's nil anyway, you can combine them into a single check and do something like this:
guard let animalImageData = animal?.img,
let animalImage = UIImage(data: animalImageData) else { return }
saveImageView.image = animalImage
or alternatively,
if let animalImageData = animal?.img, let animalImage = UIImage(data: animalImageData) {
saveImageView.image = animalImage
}
When you force-unwrap animal!.img!, it is unsafe practice and should generally be avoided since it could lead to fatal exceptions.
I'm having issues with my project. I'm new to coding. I keep getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb). It seems that the variable "image" is not producing an image and instead producing "nil". the variable "photo" is producing a name that corresponds with my JPG image name. For some the variable "image" is not able to produce that UIImage and rather is producing nil. Hopefully you can help me.
import UIKit
class Photo {
class func allPhotos() -> [Photo] {
var photos = [Photo]()
if let URL = NSBundle.mainBundle().URLForResource("Photos", withExtension: "plist") {
if let photosFromPlist = NSArray(contentsOfURL: URL) {
for dictionary in photosFromPlist {
let photo = Photo(dictionary: dictionary as! NSDictionary)
photos.append(photo)
}
}
}
return photos
}
var caption: String
var comment: String
var image: UIImage
init(caption: String, comment: String, image: UIImage) {
self.caption = caption
self.comment = comment
self.image = image
}
convenience init(dictionary: NSDictionary) {
let caption = dictionary["Caption"] as? String
let comment = dictionary["Comment"] as? String
let photo = dictionary["Photo"] as? String
let image = UIImage(named: photo!)?.decompressedImage
self.init(caption: caption!, comment: comment!, image: image!)
}
func heightForComment(font: UIFont, width: CGFloat) -> CGFloat {
let rect = NSString(string: comment).boundingRectWithSize(CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return ceil(rect.height)
}
}
I have a feeling that it has to do with the decompression of the image:
import UIKit
extension UIImage {
var decompressedImage: UIImage {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
drawAtPoint(CGPointZero)
let decompressedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return decompressedImage
}
}
Most likely it's these two lines:
let image = UIImage(named: photo!)?.decompressedImage
self.init(caption: caption!, comment: comment!, image: image!)
The first line assigns a value to image but specifically allows for a nil value. That's what the ? implies. Also, in decompressedImage (the purpose of which is... unclear) the call to UIGraphicsGetImageFromCurrentImageContext is allowed to return nil.
Then in the second line you use image! without checking whether it's nil. It is nil, according to your crash, which implies that one of the following is true:
photo doesn't actually contain the name of an image in your app bundle, or
photo has a valid name but the file is somehow corrupt to the point where UIImage can't handle it, or
decompressedImage is returning nil, because UIGraphicsGetImageFromCurrentImageContext for some reason.
There are many things going on here that might go wrong at runtime. So I'll focus on one, and advice you to be careful with force unwrapping (optionalProperty!) unless you know your optionals and in which situations it's ok to use force unwrapping. If you don't yet know the latter, you should avoid !.
Let's look at this segment of code
let image = UIImage(named: photo!)?.decompressedImage
As you mention, photo is an optional string that might be nil. But if we look at the class reference or UIImage, specifically the initialiser UIImage(named: ...), it specifies
init?(named name: String)
I.e., the parameter named should be a string. nil is not a string and hence your error.
If we proceed to assume that photo actually forcefully unwrapped to a string (path), we have our next problem; "Value of type UIImage has no member 'decompressedImage'". Looking back at the class reference for UIImage, we can't find this method here.
Anyway, I suggest read up on optionals and optional chaining in swift (if let, guard let, error handling), e.g.
Optional chaining.
In your specific case, you need to handle, at the very least, the case where expression dictionary["Photo"] as? String returns nil.
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.
I'm creating a UIButton with an image,
I have written the below code for that:
let btnImg=UIButton.buttonWithType(UIButtonType.Custom) as UIButton
let img = UIImage(named: "turn_left") as UIImage
btnImg.setTitle("Turn left", forState: UIControlState.Normal)
btnImg.setImage(img, forState: UIControlState.Normal)
btnImg.frame = CGRectMake(10, 150, 200, 45)
self.view.addSubview(btnImg)
But I got the error below at let img = UIImage(named: "turn_left") as UIImage:
Swift Compiler error:
Downcast from 'UIImage?' to 'UIImage' only unwraps optionals; did you mean to use '!'?
As error Says You have to use '!' ,
Try Below code,
let img = UIImage(named: "turn_left") as UIImage! // implicitly unwrapped
OR
let img : UIImage? = UIImage(named: "turn_left") //optional
Edit
After creating img you need to check it for nil before using it.
You can always do it in an 'if let' but note the difference in syntax depending on the version of swift.
Swift < 2.0:
if let img = img as? UIImage {
Swift 2.0:
if let img = img as UIImage! {
Note the position of the exclamation
If the UIImage initialiser cannot find the file specified (or some other error happened), it will return nil, as per Apple's documentation
Return Value
The image object for the specified file, or nil if the method could not find the specified image.
So you need to put checks in:
let img = UIImage(named: "turn_left")
if(img != nil) {
// Do some stuff with it
}
You don't need to cast a UIImage to a UIImage, that's a waste.
Edit: Full code
let img = UIImage(named: "turn_left")
if(img != nil) {
let btnImg = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
btnImg.setTitle("Turn left", forState: UIControlState.Normal)
btnImg.setImage(img, forState: UIControlState.Normal)
btnImg.frame = CGRectMake(10, 150, 200, 45)
self.view.addSubview(btnImg)
}
You may want to put an else in to set the button to a shape or something else that is more likely to work in the case "turn_left" doesn't exist.
Since UIImage(named:"something") returns an optional (because it could be nil if the methods doesn't find an appropriate image the best this is not to explicitly unwrap the result (otherwise your app will crash) but to check for the result immediately with something like that:
if let image = UIImage(named: "something"){
// now you can use image without ? because you are sure to have an image here!
image.description
}
// continue your code here using the optional power of swift's vars! :)
The approach is the following: If the image is optional means that it can be null. Functions that takes in input an optional can handle that, otherwise they usually have unexpected behavior. The UIImage(named:) can return nil and you HAVE to handle this. If you explicitly unwrap it you could have problems later.
With if let something = ... something will be automatically unwrapped in runtime and you can use it safely.
I have the following code on Swift
var image = UIImage(contentsOfFile: filePath)
if image != nil {
return image
}
It used to work great, but now on Xcode Beta 6, this returns a warning
'UIImage' is not a subtype of 'NSString'
I don't know what to do, I tried different things like
if let image = UIImage(contentsOfFile: filePath) {
return image
}
But the error changes to:
Bound value in a conditional binding must be of Optional type
Is this a bug on Xcode6 beta 6 or am I doing something wrong?
Update
Swift now added the concept of failable initializers and UIImage is now one of them. The initializer returns an Optional so if the image cannot be created it will return nil.
Variables by default cannot be nil. That is why you are getting an error when trying to compare image to nil. You need to explicitly define your variable as optional:
let image: UIImage? = UIImage(contentsOfFile: filePath)
if image != nil {
return image!
}
The simplest way to check if an image has content (> nil) is:
if image.size.width != 0 { do someting}
func imageIsNullOrNot(imageName : UIImage)-> Bool
{
let size = CGSize(width: 0, height: 0)
if (imageName.size.width == size.width)
{
return false
}
else
{
return true
}
}
the Above method call Like as :
if (imageIsNullOrNot(selectedImage))
{
//image is not null
}
else
{
//image is null
}
here, i check image size.
Init, that you are call init?(contentsOfFile path: String) the ? means that it returns optional value.
You should check optional vars for nil before use it.
Shorter, than accepted answer and Swift-style way, than named Optional Chaining to do that:
if let image = UIImage(contentsOfFile: filePath) {
return image
}
You can check it's imageAsset like this:
if image.imageAsset != nil
{
// image is not null
}
else
{
//image is null
}
You can check for it's width, which would be 0 if no image is uploaded.
if(image.size.width != 0){
print("image found")
} else {
print("image is null")
}