-8

I am trying to retrieve the postImageUrl from firebase but for some reason I'm getting a error from a unwrapping nil with the postImageUrl. How can I make this code work so I can retrieve the image url from firebase without causing a crash?

Code Screenshot

Firebase Database

Trai Nguyen
  • 809
  • 1
  • 8
  • 22
sta8er
  • 1
  • 3
  • My guess is `postURL` is actually `nil`. Instead of force unwrapping things you should be using `guard let ... else` to verify that the value is valid, it's kind of the point of using optionals – MadProgrammer Dec 21 '19 at 02:07
  • Share a snippet of the post in the Firebase database so we can see what data you are trying to load into the postImageUrl – Antony Harfield Dec 21 '19 at 02:15
  • Perhaps you only need to do `let postImageUrl = dict["postImageUrl"] as! String` on line 97. – Antony Harfield Dec 21 '19 at 02:17
  • i tried that but it crash. i get the same error – sta8er Dec 21 '19 at 02:19
  • 2
    Please post your code inline instead of as a screenshot. – Charles Srstka Dec 21 '19 at 02:24
  • Welcome to SO. Please don’t include images or links in your questions. Include code and structures as text. Links break and if they do, it invalidates the question. To get your Firebase structure, use the Firebase console->Export JSON and copy and paste a snippet of your structure. See [images and links are evil](http://idownvotedbecau.se/imageofcode). Images and links are not searchable so they may not be of use to future readers. – Jay Dec 21 '19 at 15:11

3 Answers3

0

In general, you should avoid the ! force-unwrap operator unless you can 100% prove that the value will never be nil, which should be a tiny minority of the time (usually when loading files included inside your application's bundle). This clearly isn't the case here, since the value is nil, so you should either use if let or guard let to unwrap the value, handling the case where it is nil, or you can use the ?? operator to provide a default value like so:

doSomethingWith(foo ?? "this string gets passed if foo is nil")

Depending on what your Post object is supposed to do, it's also possible that it might actually be appropriate for it to contain a nil value for imageURL. In this case, you may just want to declare its imageURL property as an optional by adding an ? to the end of its type:

struct Post: Codable {
    ...
    let imageURL: URL? // or String? if that's what it is
    ...
}

In this case, you would unwrap the imageURL property later, when it comes time to use it.

Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
0

It's best practice to handle optionals by safely unwrapping them and providing default values in case of nil or not executing code that could crash the app.

Additionally, Firebase snapshots are quite powerful and enable you to easily drill down into child nodes.

Here's some updated code that shows those two techniques.

func gerAllFeedPosts() {
    REF_FEED.observeSingleEvent(of: .value, with: { snapshot in
        let allPosts = snapshot.children.allObjects as! [DataSnapshot]
        for postSnap in allPosts { //if there are no posts, no closure code will run
            let authorSnap = postSnap.childSnapshot(forPath: "author")
            let uid = authorSnap.childSnapshot(forPath: "uid").value as? String ?? "NO UID!"
            let username = authorSnap.childSnapshot(forPath: "username").value as? String ?? "NO USERNAME!"
Jay
  • 34,438
  • 18
  • 52
  • 81
-2

change this line of code 93:

let author = dict!["author"] as? [String: AnyObject]
Zain
  • 153
  • 9
  • @GerardoLeon The issue here is the that this is unwrapping an optional in an unsafe manner - if dict is nil, the app will crash. So safely unwrapping it is best practice and/or providing default values in those cases is a good idea. Also current swift code would be `[String: Any]`. There are also alternatives for performing this function - see my answer. – Jay Dec 21 '19 at 15:42
  • @Jay firebase dictionary instance in always [String: AnyObject]. you need to check firebase documentation. – Zain Dec 21 '19 at 17:39
  • Lol. Use AnyObject when you need the flexibility of an untyped object or when you use bridged Objective-C methods and properties that return an untyped result. While it appears in the somewhat outdated documentation, a quick test in Playground should be very revealing. Try this `let x: [String: AnyObject] = ["key": "value"]` and then try this `let y: [String: Any] = ["key": "value"]` and check out the results. Also check out [this answer](https://stackoverflow.com/questions/25809168/anyobject-and-any-in-swift) for some other reading. AnyObject is not wrong, just 'old'. – Jay Dec 21 '19 at 23:29