Object is nil but code interpret not as nil - ios

I want to check if an object I get from the server is nil or not, if nil I want to use a placeholder image, if not nil I want to use the image from the url. Debugger says imageUrl is nil, but my code evaluates it as not nil.
the code always crash at
providerImg.sd_setImageWithURL(NSURL(string: GPProfiles[indexPath.row]["image"] as! String))
I have also tried this
let imageUrl = GPProfiles[indexPath.row]["image"]
if imageUrl != nil {
providerImg.sd_setImageWithURL(NSURL(string: GPProfiles[indexPath.row]["image"] as! String))
} else{
providerImg.image = UIImage(named: "placeholderImage.png")
}
How can I check if an object is nil ??? Thanks
UPDATE TO ANSVWER BY #andre-slotta

try this:
if let imageUrl = GPProfiles[indexPath.row]["image"] as? String {
...
}
since your != nil check does not seem to work here you get some more info about nil, NULL and NSNull: nshipster.com/nil

Related

Found nil value in dictionary when it isn't nil

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!

Firebase reference is 'variable not available' when downloading picture in Swift

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.

Getting image from Core Data

I'm working on a Cocktailapp and want to save my image data to Core Data.
I watched some tutorials and did the same but it's still not working an I don't know why.
I have an Array with all titles for the images:
let imagesAperitif: [String] = ["americano.jpg", "daiquiri.jpg",
"frozen daiquiri.jpg",
"banana frozen daiquiri.jpg", "bronx.jpg", "kir.jpg",
"hugo.jpg", "Manhattann.jpg", "manhattan dry.jpg", "manhattan medium.jpg", "margarita.jpg",
"martini dry.jpg",...
Thats where I call my method for saving the images to Core Data:
setCocktails(nameInsert, zutaten: zutatenInsert, zubereitung: zubereitungInsert, dekoration: dekorationInsert, stil: stilInsert, bild: UIImage(named: imagesAperitif[index])!)
That's a part from the code of saveCocktails method:
let imageData = NSData(data: UIImageJPEGRepresentation(bild, 1.0)!)
eintrag.setValue(imageData, forKey: "bild")
do {
try managedContext.save()
That's part of the fetching method:
let fetchRequest = NSFetchRequest(entityName: "Cocktail")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
cocktails = results as! [NSManagedObject]
And here I want to get my image back from NSData:
imagesAperitif.append(UIImage(data: eintrag.valueForKey("bild") as! NSData)!)
But the App crashes with this line and I get a "fatal error: unexpectedly found nil while unwrapping an Optional value" error.
Is anybody able to explain this to me because I don't know what to change. Everything I tried went also wrong.
You may want to check nil for eintrag.valueForKey("bild") before case it to NSData
As
func valueForKey(_ key: String) -> AnyObject?
And it's always save to check nil before you append UIImage(data: eintrag.valueForKey("bild") as! NSData)
(I like using guard so here goes :) )
So what I would do here since it looks like the inserting of the NSData object fails:
// We are simultaniously unwrapping objects and checking if objects are nil.
guard let imgAsNSData: NSData = UIImageJPEGRepresentation(bild, 1.0),
let entity: Cocktail = eintrag as? Cocktail else {
// Stop executing the method here, there is no point in going further. Handle any errors here! Either imgAsNSData is nil, or could not cast to your class. A guard statement handles it's errors here.
return
}
// At this point we know we have an NSData object. Assign it to the entity.
entity.bild = imgAsNSData
do {
// Save our entity.
try managedContext.save()
} catch {
// Handle error
}
Fetching:
let fetchRequest = NSFetchRequest(entityName: "Cocktail")
do {
let results: [NSManagedObject] = try managedContext.executeFetchRequest(fetchRequest)
guard let cocktails = results as? [Cocktail] else {
// Could not cast to an array of Cocktail objects.
return
}
// Do stuff with the cocktails object.
Add to your array:
// 1: Check if entity not is nil
// 2: Check if entity's bild property not is nil.
// 3: Check if we can create an image using the NSData
guard let cocktail: Cocktail = eintrag as? Cocktail,
let imgAsNSData: NSData = cocktail.bild,
let image: UIImage = UIImage(data: imgAsNSData) else {
// Required values are nil. Cannot proceed.
return
}
imagesAperitif.append(image)
Untested code so be careful :)

Check if url image exist

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
}

How to check if imageView is not nil in swift?

I have a fatal error while unwrapping an optional value in swift.
I have a profile ViewController with a background image and an avatar image witch are the same.
When the user has not an image set, i ve got this fatal error, instead i would like to add a "by default image Shape".
How could i check if image isn't nil ?
This is my code :
var currentUser = PFUser.currentUser()
let User = currentUser as PFUser
let userImage:PFFile = User["profileImage"] as PFFile {
userImage.getDataInBackgroundWithBlock{(imageData:NSData!, error:NSError!)-> Void in
if !(error != nil) {
var image:UIImage! = UIImage(data: imageData)
if image != 0 {
self.backgroundImageUser.image = image
self.avatarUserView.image = image
}
else if image == 0 {
self.backgroundImageUser.image = UIImage(named: "Shape")
self.avatarUserView.image = UIImage(named: "Shape")
}
}}}
Try this:
userImage.getDataInBackgroundWithBlock{(imageData:NSData?, error:NSError?)-> Void in
if let image = UIImage(data: imageData) {
self.backgroundImageUser.image = image
self.avatarUserView.image = image
}
else {
self.backgroundImageUser.image = UIImage(named: "Shape")
self.avatarUserView.image = UIImage(named: "Shape")
}
}
let image : UIImage? = img
if image != nil{
}else{
}
In order to get this working, you have to understand Optional Chaining.
As the Apple Documentation says:
Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.
So if you want an object to get a nil Value, you have to declare it as Optional. To declare the object as Optional You have to place a question mark after the value.
In your example it will look just like this:
var image:UIImage? ;
image = UIImage(data: imageData) ;
And by declaring this UIImage as Optional, it will be initialized with nil.
swift 5
var imageBottom = UIImage.init(named: "contactUs")
if imageBottom != nil {
imageBottom = imageBottom?.withRenderingMode(.alwaysTemplate)
bottomImageview.image = imageBottom
}
In fact the problem was up, as you can see in the edited post, i had a the userImage declaration not optional.
So now everything work fine with :
var currentUser = PFUser.currentUser()
let User = currentUser as PFUser
if let userImage:PFFile = User["profileImage"] as? PFFile {
userImage.getDataInBackgroundWithBlock{(imageData:NSData!, error:NSError!)-> Void in
if !(error != nil) {
var image :UIImage! = UIImage(data: imageData)
self.backgroundImageUser.image = image
self.avatarUserView.image = image
}
}}
else {
self.backgroundImageUser.image = UIImage(named: "Shape")
self.avatarUserView.image = UIImage(named: "Shape")
}

Resources