Brkr Brkr - 7 days ago 9
Swift Question

Firebase Storage Image Download

I am trying to download image from Firebase storage.

func downloadThumbnail(thumbnail: String) -> URL {
var thumb: URL!
let _ = DataService.dataService.TAG_PHOTO_REF.child("\(thumbnail)").downloadURL { (thumbnailUrl, error) in
if error != nil {
print(error?.localizedDescription as Any)
} else {
thumb = thumbnailUrl
}
}
return thumb
}

cell.photo.kf.setImage(with: downloadThumbnail(thumbnail: selectedTag.thumbnail))


When I run this code I got


fatal error: unexpectedly found nil while unwrapping an Optional value


with
return thumb
line.

But if I run only
print(thumbnailUrl)
instead of return, it prints correct thumbnail url. Can anyone know why I got this error?

Thanks.

Answer

You can not guarantee that thumb will never be nil. Because of this, you should not be using !. Because you have no control over it and have not set it manually, you need to make it an optional.

var thumb: URL?

Secondly, you have an internet call. You are returning thumb before you get a response from that call, because of that, thumb is nil, but you told us with the ! that that is impossible, so you crash.

If you put in breakpoints, you should notice that you will hit return thumb on your method before you hit the if error != nil line. You can't use a return for this, because the method will always return before it gets a response from firebase, so your URL will always be nil. I would instead send a URL in a completion.

I haven't checked the firebase code, but if all is right with it, this is the order you want.

So:

func downloadThumbnail(thumbnail: String,withCompletion comp: @escaping (URL?, Error?) -> ()) {
  let _ = DataService.dataService.TAG_PHOTO_REF.child("\(thumbnail)").downloadURL { (thumbnailUrl, error) in
    if error != nil {
        print(error?.localizedDescription as Any)
        comp(nil, error)
    } else {
        comp(thumbnailUrl, nil)
    }
  }
}

So when you call it somewhere else:

func getMyImage(cell: UITableViewCell) {
  downloadThumbnail(thumbnail: selectedTag.thumbnail) { (thumbnailUrl, error) in 
    if error != nil {
      //show some sort of alert for the user here? or do something to handle the error?
    } else {
      //the url is an optional URL, so check to make sure it isn't nil
      if let url = thumbnailUrl {
        cell.photo.kf.setImage(with: url)
      } else {
        //you didn't get an error from your firebase response
        //but the thumbnail url it gave you is broken for some reason
        //so again, do something about your error here
    }
  }
}

If this doesn't match the design pattern of your app, let me know. I assumed you were using a tableview and that these methods might be in different classes.