0

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.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
sametbilgi
  • 582
  • 2
  • 7
  • 29

1 Answers1

2

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.

Kayla Galway
  • 662
  • 4
  • 7