I'm trying to check if a url image exist using a if statement. However when trying to test it by wrong image url it keep returning:
fatal error: unexpectedly found nil while unwrapping an Optional value.
code:
var httpUrl = subJson["image_url"].stringValue
let url = NSURL(string: httpUrl)
let data = NSData(contentsOfURL: url!)
if UIImage(data: data!) != nil {
}
You can do it this way:
var httpUrl = subJson["image_url"].stringValue
if let data = NSData(contentsOfURL: url) {
//assign your image here
}
Other answers are telling you to unwrap the optional, but really the issue is that you are force-unwrapping the optional with !, despite it being nil.
When you write something! what you are saying is “something might be nil, but if it is, I want my program to crash”.
The reason a call might return nil is if the result is not valid – for example, if you try to fetch a key from a dictionary that isn’t there, or that a URL doesn’t point to a valid downloadable image.
You can combine the check for nil with an if statement that unwraps the optional and returns a non-optional value so long as the value wasn’t nil. You can also chain them together, so if you need to unwrap a value, then pass it into a call that also returns an optional, you can do it all in one if statement:
if let httpUrl = subJson["image_url"].string,
url = NSURL(string: httpUrl),
data = NSData(contentsOfURL: url),
image = UIImage(data: data)
{
// use image value
}
else {
// log some error
}
Note, on the first line, the call is to .string rather than .stringValue – .string also returns an optional with nil if the value isn’t present.
Of course, combining all these unwraps together means you can’t tell which one failed, so you may want to break them out into separate statements instead.
This code is tested and successful: if image url not exists no crash.
let url: NSURL = NSURL(string: "http://www.example.com/images/image.png")!
do {
let imgData = try NSData(contentsOfURL: url, options: NSDataReadingOptions())
ImageView?.image = UIImage(data: imgData)
} catch {
print(error)
}
You have to unwrap the optional like this:
if let image = data {
// use image here
} else {
// the data is nil
}
Related
This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 4 years ago.
This question might be a duplicate, but I think my case is different.
I built an app to fetch news articles from different sources. The problem I have is some sources may not include article image which causing my app to crash, please have a look at my code:
extension UIImageView {
func downloadImage(from url: String) {
let urlRequest = URLRequest(url: URL(string: url)!) // I get Fatal error on this line
let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in
if error != nil {
print(error as Any)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}
I tried to modify the code to not force unwrap the image if found nil, but It just didn't work, because I get other errors in other places.
If anyone can point the mistake, please, by writing how the code should be in case image found nil to not crash the app. It will be extremely appreciated!
The URL is force unwrapped. You should unwrap optional by using guard let construction:
guard let url = URL(string: url) else { return }
let urlRequest = URLRequest(url: url)
I tried to modify the code to not force unwrap the image if found nil,
Well yes it's duplicated question.
However this problem is solved by OptionalChaining i recommend reading about it Here,
Now for the part on how to solve it quickly, you can try to add this line under your request, which is going to check if its nil or not, and incase it was nil it will simply escape the closure without causing any crashes or problems.
guard let data = data else {return}
There are many types of OptionalChaining, each one has its own usage but they all serve the same propose of handling the nil values without causing a crashes.
DispatchQueue.main.async {
guard let data = data {
self.image = UIImage(data: data)
} else {
print(value is nil.)
}
}
This is the way to safe unwrap the optional value. It will not crash if Data is nil on unwrapping .
I want to create URL from string in dictionary, but when I initialize it, the guard statement goes to else statement, because values["Image"] is nil and return the function. Here is a piece of my code
guard let imageURLInDatabase = URL(string: values["Image"]!) else { return }
let data = NSData(contentsOf: imageURLInDatabase)
I have create afew breakpoint in my code:
And here is my console log at this breakpoint:
What did I miss?
P.S
I tried to do it like:
let imageURLInDatabase = URL(string: values["Image"]!)
but I got error message unexpectedly found nil while unwrapping an optional value
Edit 1:
I tried to do it like
guard let imageString = values["Image"] else{return}
guard let imageURLInDatabase = URL(string: imageString) else{
return}
let data = NSData(contentsOf: imageURLInDatabase)
And set breakpoints:
So values["Image"] can't be nil
Edit 2:
This is what is in values["Image"]:
some : "https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
The problem is the extra quotation mark at the end of the URL string. Try this:
let s = "https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
let url = URL(string:s)
You'll get nil.
The problem isn't that values["Image"] is nil. The problem is that values["Image"] isn't a value URL string.
Make sure you properly encode spaces and other special characters in the URL.
And as a side note, do not use NSData, use Data.
According to your trace, the problem isn't that value["Image"] is nil. If that were the case, you would have crashed rather than called return. Your problem is that whatever the value of value["Image"], it is not a valid URL. Without seeing the value, it's difficult to know exactly what is wrong with it, but it is malformed in some way.
This is because the dictionary values does not contains the key Image. So values['Image'] will return nil, and force unwrapping a nil will crash the app.
Try using guard else statements to unwrap it
guard let imageValue = values["Image"] as? String else {
//imageValue is nil here, handle accordingly
return
}
guard let imageURLInDatabase = URL(string: imageValue) else {
//imageURLInDatabase is nil here, handle accordingly
return
}
let data = NSData(contentsOf: imageURLInDatabase)
Edit 1:
With your updated question, and the breakpoint image, values["Image"] is not null, imageURLInDatabase is nil due to which it goes to else case.
The reason could be that values["Image"] might not be returning a valid url, due to which URL(string: ..) fails.
Edit 2 :
Check the string url you just shared
"https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
has an extra quote in the end!
Title says everything. I'm just unable to download an image from Firebase Storage dir. Here is the snippet of the code which calls the function for setting data and it also calls the function which tries to download the picture:
for element in Dict {
if let itemDict = element.value as? [String:AnyObject]{
let name = itemDict["name"] as! String
let price = itemDict["price"] as! Float
let imageObject = itemDict["image"] as! NSDictionary
let hash = imageObject["hash"] as! String
let storageDir = imageObject["storageDir"] as! String
let image:UIImage = self.downloadImageProductFromFirebase(append: hash)!
let product = Product(name: name, image: image, imageName:hash, price: price, storageDir : storageDir)
self.productList.append(product)
}
}
print(Dict)
self.myTable.reloadData()
And here is the code which tries to download the image:
func downloadImageProductFromFirebase(append:String) -> UIImage?{
let gsReference = Storage.storage().reference(forURL: "gs://fridgeapp-3e2c6.appspot.com/productImages/productImages/" + append)
var image : UIImage?
gsReference.downloadURL(completion: { (url, error) in
if error != nil {
print(error.debugDescription)
return
}
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error.debugDescription)
return
}
guard let imageData = UIImage(data: data!) else { return }
DispatchQueue.main.async {
image = imageData
}
}).resume()
})
return image
}
But, for some reason, it crashes just when calling this last function, saying that "fatal error: unexpectedly found nil while unwrapping an Optional value". I tried to use the debugger, and I found out that Firebase reference to Storage variable says "variable not available".
Could someone of you guys help me with this? I think I read the Firebase doc about a hundred times, and still can't get the point.
Thank you!
Downloading an image from a remote server is an asynchronous task, that means that the result is not immediately available. This is the reason that gsReference.downloadURL accepts a completion callback as an argument, and has no return value.
Since your function (downloadImageProductFromFirebase) is simply a wrapper to gsReference.downloadURL, it should also accept a completion callback as an argument, and should not have a return value (i.e. remove the -> UIImage?).
When you call self.downloadImageProductFromFirebase pass in a closure that receives the image, finds the index of the corresponding product in productList, and sets itself as the cell's image (assuming you're showing the image in the cell).
See this answer for how to asynchronously set cell images.
I have a question on how to use the new error handling in Swift.
I'm reading contents of a file into a data object:
var overallData: Data?
//load file contents into data object
let dataFileURL = NSURL(string: fileName)
do {
overallData = try Data(contentsOf: dataFileURL as! URL)
} catch {
print("\(error)")
}
The problem is that I always encounter this error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
The problem is that the overallData object is set as nil. But if I don't define a data variable outside the do-catch,
let dataFileURL = NSURL(string: fileName)
do {
overallData = try Data(contentsOf: dataFileURL as! URL)
} catch {
print("\(error)")
}
Later on, I can't use the overallData object because the system keeps telling me it's a variable not defined yet. So it looks like new variables defined in the do-catch loop can only be locally accessed inside the loop.
Do you know how to solve this problem? I do need to use the overallData object elsewhere.
The following answer assumes your error is with the line:
overallData = try Data(contentsOf: dataFileURL as! URL)
If you are getting the "fatal error" on another line, please update your question.
Your error has nothing to do with the do/catch/try.
Your problem is the force unwrapping of dataFileURL which is nil.
Your problem is this line:
let dataFileURL = NSURL(string: fileName)
This is returning nil because fileName isn't a valid URL.
Assuming fileName is a path to a local file, you need to do:
let dataFileURL = URL(fileURLWithPath: fileName)
Also note the use of URL instead of NSURL. There is no sense in using NSURL in Swift 3.
I have an image url string:
var remoteImage: String = "http://server.com/wall-e.jpg"
I then construct a UIImage to download on a separate thread using Grand Central Dispatch with remoteImage as the NSURL string parameter:
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)!)!)
When it is finished and I return back to the main thread, I have it save internally:
UIImageJPEGRepresentation(getImage, 1.0).writeToFile(imagePath, atomically: true)
On Wi-fi and LTE it downloads fine, but when testing edge cases such as on an Edge network (no pun intended), I inconsistently get the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Now I thought I would be safe by making sure that it wasn't nil by adding in:
if getImage != nil { ... }
But it didn't seem to make a difference. It still gets the error and highlights the let getImage as written above. What am I doing wrong here? Should I be checking nil in a different manner or method?
I would recommend you to use AsyncRequest to fetch and download the image and saved it locally.
As you didn't posted any of code of your problem.
So i am posting a sample working for me.
Sample for downloading and saving image locally
var url = NSURL(string : "http://freedwallpaper.com/wp-content/uploads/2014/09/Tattoo-Girl.jpg")
let urlrequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlrequest, queue: NSOperationQueue.mainQueue(), completionHandler: {
response ,data , error in
if error != nil
{
println("error occurs")
}
else
{
let image = UIImage(data: data)
/* Storing image locally */
var documentsDirectory:String?
var paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
println(paths)
if paths.count > 0{
documentsDirectory = paths[0] as? String
var savePath = documentsDirectory! + "/bach.jpg"
NSFileManager.defaultManager().createFileAtPath(savePath, contents: data, attributes: nil)
self.bach.image = UIImage(named: savePath)
}
}
})
}
The error, does, in fact lie on the line:
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)!)!)
The reason is that it's not the UIImage that is initially returning nil, it is probably NSData returning nil. You could check if NSData is returning nil, and then create the UIImage object instead.
EDIT: What the particular line of code is doing is it is assuming that NSData is always returning a non-nil value, which may not be true when you are not connected. When you're not connected, it gets a nil value, which you are trying to say will never be a nil value using the exclamation mark (!).
I suggest you read further on how Swift works. For this particular example, take a look at what the exclamation marks actually mean in Swift: What does an exclamation mark mean in the Swift language?