简体   繁体   中英

How to know which initializer to use for reading data(Firebase)

I've got two initializers:

    struct UserInfo{
let ref: DatabaseReference?
let key: String
let firstName: String
let lastName: String
let username: String
let pictureURL : String?
let admin : Bool

init(firstName: String, lastName:String,username:String,pictureURL:String?,admin:Bool, key:String = "" ){
    self.ref = nil
    self.key = key
    self.firstName = firstName
    self.lastName = lastName
    self.username = username
    self.pictureURL = pictureURL
    self.admin = admin
    
}

init?(snapshot:DataSnapshot){
    guard let value = snapshot.value as? [String:AnyObject],
          let firstName = value["firstName"] as? String,
          let lastName = value["lastName"] as? String,
          let username = value["userName"] as? String,
          let profilePic = value["pictureURL"] as? String,
          let admin = value["isAdmin"] as? Bool
            
    else {return nil}

    self.ref = snapshot.ref
    self.key = snapshot.key
    self.firstName = firstName
    self.lastName = lastName
    self.username = username
    self.pictureURL = profilePic
    self.admin = admin
}
func toAnyObject()-> Any{
    return [
        "firstName": firstName,
        "lastName": lastName,
        "username": username,
        "pictureURL":pictureURL as Any,
        "isAdmin": admin
    ]
}

}

For reading most recent data I use this method combined with first init and it works:

   let completed =
    DataObjects.infoRef.child(uid!).observe(.value){ snapshot,error in
        var newArray: [UserInfo] = []
            if let dictionary = snapshot.value as? [String:Any]{
                let username = dictionary["username"] as! String
                let firstName = dictionary["firstName"] as! String
                let lastName = dictionary["lastName"] as! String
                let profilePic = dictionary["pictureURL"] as? String
                let admin = dictionary["isAdmin"] as! Bool
                let userInformation = UserInfo(firstName: firstName, lastName: 
           lastName, username: username,pictureURL: profilePic, admin: admin)
                newArray.append(userInformation)
                print(newArray)
                completion(.success(newArray))
                print(newArray)
            }

Why and when do I need to use second init??

In Firebase tutorial on raywenderlich.com we gat example about: Synchronizing Data to the Table View using second init:

    let completed = ref.observe(.value) { snapshot in
 // 2
 var newItems: [GroceryItem] = []
 // 3
 for child in snapshot.children {
  // 4
  if
  let snapshot = child as? DataSnapshot,
  let groceryItem = GroceryItem(snapshot: snapshot) {
  newItems.append(groceryItem)
 }
}
 // 5
 self.items = newItems
 self.tableView.reloadData()

But my method works the same with first init.

The question is really asking about two things that functionally work the same.

In one case the snapshot is being "broken down" into its raw data (strings etc) within the firebase closure

   DataObjects.infoRef.child(uid!).observe(.value){ snapshot,error in
      let username = dictionary["username"] as! String
      let firstName = dictionary["firstName"] as! String
      let lastName = dictionary["lastName"] as! String
      let userInformation = UserInfo(firstName: firstName, lastName: lastName...

and then passing that raw data to the struct. That object is then added to the array

In the second case the snapshot itself is passed to the struct

init?(snapshot:DataSnapshot) {
    guard let value = snapshot.value as? [String:AnyObject],

and the snapshot is broken down into it's raw data within the object.

The both function the same.

It's a matter of readability and personal preference. Generally speaking having initializers etc within an object can make the code a bit more readable, the object more reusable and less code - see this pseudo code

DataObjects.infoRef.child(uid!).observe(.value){ snapshot, error in
    let user = UserInfo(snapshot)
    self.newArray.append(user)
})

That's pretty tight code.

Imagine if there were 10 places you wanted to access those objects within your app. In your first case, that code would have to be replicated 10 times - which could be a lot more troubleshooting. In my example above, the object itself does the heavy lifting so accessing them requires far less code.

Two other things. You may want to consider using.childSnapshot to access the data within a snapshot instead of a dictionary (either way works)

let userName = snapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"

and please avoid force unwrapping optional vars

child(uid!)

as it will cause unstable code and random, unexplained crashes. This would be better

guard let uid = maybeUid else { return } //or handle the error

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM