2

I am retrieving Objects from the Firebase DB and I need to cast them to a custom struct class object

Class:

struct Request {
    var Address: String!
    var Position: Position!
    var RequestID: String!
    var Status: String!
}

The function that gets the snapshot from my Firebase DB:

self.ref.child("requests").observe(.childAdded, with: { snapshot in

    //I need to cast this snapshot object to a new Request object here

    let dataChange = snapshot.value as? [String:AnyObject]

    print(dataChange)

})

How can I get this done?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jay
  • 4,873
  • 7
  • 72
  • 137

2 Answers2

6

A couple of things. Firebase doesn't have objects - it's a JSON structure. When you get the snapshot.value like so:

let dataChange = snapshot.value as? [String:AnyObject]

The [String: AnyObject] is defining the data as a Dictionary.

You can then access the key:value pairs in dataChange like this

let address = dataChange["address"]

and

let position = dataChange["position"]

From there you can either create new objects and populate them within the closure (adding them to an array for example) or put more intelligence in the object and pass the dictionary and let the object populate itself.

The following is pseudo code but it presents the process:

//create the object and populate it 'manually'
self.ref.child("requests").observe(.childAdded, with: { snapshot in

    let dataChange = snapshot.value as? [String:AnyObject]

    let aRequest = Request()
    aRequest.address = dataChange["address"]
    aRequest.position = dataChange["position"]
    self.requestArray.append(aRequest)
})

or

Class Request {

   var address = ""
   var position = ""

   func initWithDict(aDict: [String: AnyObject]) {
    self.address = aDict["address"]
    self.position = aDict["position"]
   }

}

//let the object populate itself.
self.ref.child("requests").observe(.childAdded, with: { snapshot in

    let dataChange = snapshot.value as? [String:AnyObject]
    let aRequest = Request(initWithDict: dataChange)
    self.requestArray.append(aRequest)
})
Jay
  • 34,438
  • 18
  • 52
  • 81
  • Thank you for the brilliant explaination! However, I came across a weird problem. At time when I execute through the line: `let address = dataChange["address"]', it crashes because the value "address" is actually read as **Address**. In that case I tried: `let address = dataChange["Address"]`. Everything was working well until suddenly it started reading it as let `address = dataChange["address"]`. Why does it keep changing the JSON value's capitalization? – Jay Dec 31 '16 at 03:00
  • @RickGrimesLikesWalkerSoup That's directly related to your Firebase Structure. I would guess you may have some key's labeled 'Address' and others 'address' - they have to be consistent. You can avoid the crash by using and if let address = dataChange["address"] technique but ultimately the data (key names) should be consistent. – Jay Dec 31 '16 at 14:19
  • Haha thats the hack that I turned to in the end. I checked if it's nil and if so, I change the capitalisation and check again. Anyway thanks Jay. Your solution works – Jay Dec 31 '16 at 14:54
6

If your struct has a lot of fields, it's easier to do like this (Swift 4+):

struct Request: Decodable {
    var Address: String
    var RequestID: String
    var Status: String
}

self.ref.child("requests").observe(.childAdded, with: { snapshot in
    guard let data = try? JSONSerialization.data(withJSONObject: snapshot.value as Any, options: []) else { return }
    let yourStructObject = try? JSONDecoder().decode(Request.self, from: data)
}
Community
  • 1
  • 1
IvanPavliuk
  • 1,460
  • 1
  • 21
  • 16