'Can't get DatabaseReference for user in Firebase

I have two initializers. First where snapshot is being "broken down" into its raw data (strings etc) within the firebase closure and the second is convenient one.

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

init(firstName: String, lastName:String,username:String,pictureURL:String?,training:[String]?,uid:String,admin:Bool, key:String = "" ){
    self.ref = nil
    self.key = key
    self.firstName = firstName
    self.lastName = lastName
    self.username = username
    self.pictureURL = pictureURL
    self.training = training
    self.uid = uid
    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 training = value["Training"] as? [String],
          let uid = value["uid"] 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.training = training
    self.uid = uid
    self.admin = admin
}

For getting data fist init works well but when I try to get data with second init my ref value is nill.

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 training = dictionary["Training"] as? [String]
                let uid = dictionary["uid"] as! String
                let admin = dictionary["isAdmin"] as! Bool
                let userInformation = UserInfo(firstName: firstName, lastName: lastName, username: username,pictureURL: profilePic,training: training, uid: uid, admin: admin)
                let user = UserInfo(snapshot: snapshot)

I set breakpoint at user and userInformations and this is what I get.

user:

user

userInformations:

enter image description here



Solution 1:[1]

This is more of guidance and observation than an answer; maybe it will help.

If you look at your code, the userInformation and user vars are initialized one after the other:

let userInformation = UserInfo(firstName:...
let user = UserInfo(snapshot: snapshot)

So then looking at the screenshots, the first one has the ref var being nil

enter image description here

Which is correct because that the first init call doesn't init the ref var

init(firstName: ...
    self.ref = nil

but then when the second line executes, it does init the ref var in the init

init?(snapshot:...
   self.ref = snapshot.ref

so then it's populated

enter image description here

and then, I created a minimal version of your struct

struct UserInfo{
    let firstName: String

    init(firstName: String ){
        self.firstName = firstName
    }

    init?(snapshot: DataSnapshot) {
        guard let value = snapshot.value as? [String:Any], let firstName = value["name"] as? String else { return nil }

        self.firstName = firstName
        print(snapshot.ref) //this prints the path the the snapshot e.g. it's not nil
    }
}

and then code to populate the two vars and print them to console

func test() {
    let uid = "uid_0"
    self.ref.child("users").child(uid).observe(.value){ snapshot,error in
        var newArray: [UserInfo] = []
        if let dictionary = snapshot.value as? [String:Any] {
            let firstName = dictionary["name"] as! String
            let userInformation = UserInfo(firstName: firstName)
            let user = UserInfo(snapshot: snapshot)

            print(userInformation)
            print(user)
        }
    }
}

and when I run the code, both are correctly populated

UserInfo(firstName: "Jay")
Optional(MyFirebase.ViewController.UserInfo(firstName: "Jay"))

Of course the optional var (second printed line) is showing as optional because it was defined that way.

So the bottom line is that I don't think the issue in the question is actually an issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jay