set the value for a variable once or initialize a variable - Swift - swift

Im using Firebase Firestore as my database, and I want to limit the number of calls to the database so my plan is to initialize an object once and have it ready for me to use anywhere throughout my app. What I want to do is basically give the publicUsername a value collected from the database once, so once publicUsername has a value, I don't want to call to the database anymore. I then want to call publicUsername through my app such as when I want to show the user their username I can just call the publicUsername value as so: usernameLabel.text = publicUsername.
Here are 2 methods I've tried using, but no luck!:
let publicUsername = Uzer().uzername
class Uzer {
var uzername = ""
init() {
let uid = Auth.auth().currentUser?.uid
let database = Firestore.firestore().collection("Users").document(uid!)
database.getDocument { (docSnapshot, error) in
guard let docSnapshot = docSnapshot, docSnapshot.exists else {return}
let mydata = docSnapshot.data()
let username = mydata!["Username"] as? String ?? ""
self.uzername = username
}
}
}
OR
let publicUsername = User().username
class Users {
var username = ""
func returnUsername () -> String {
if username == "" {
let uid = Auth.auth().currentUser?.uid
let database = Firestore.firestore().collection("Users").document(uid!)
database.getDocument { (docSnapshot, error) in
guard let docSnapshot = docSnapshot, docSnapshot.exists else {return}
let mydata = docSnapshot.data()
let username = mydata!["Username"] as? String ?? ""
self.username = username
}
return username
} else {
return username
}
}
}

Related

How to automatically update information changed in Firestore

I have this code to display username that was stored in Firestore when signing up:
func displayUserName(){
let db = Firestore.firestore()
if let uid = user?.uid{
db.collection("PROFILE").document(uid).getDocument { (snap, err) in
guard let data = snap else {return}
let firstname = data.get("firstName") as! String
self.firstName = firstname
}
}
}
but, when I change the name in Firestore, I need to relaunch the app so it can update. is it possible to update this name without needing to relaunch the app?
Based on the comment given, I just changed getDocuments for addSnapshotListener
db.collection("PROFILE").document(uid).addSnapshotListener { (documentSnapshot, error) in
guard let datas = documentSnapshot else {return}
let firstname = datas.get("firstName") as! String
self.firstName = firstname
}

Setting up Nested Structs and populating via FireStore [Swift]

I have two structs, one nested within the other:
struct User {
let uid: String
let name: String
var pack: [Doggo]
}
struct Doggo {
let dogUid: String
let dogName: String
let dogBreed: String
let dogBorn: String
let dogProfileImageURL: String
}
Is the following code the proper way to access the firebase data for each?
guard let userUid = Auth.auth().currentUser?.uid else { return }
let userRef = self.db.collection("users").document(userUid)
let packRef = self.db.collection("users").document(userUid).collection("pack")
userRef.getDocument { (document, error) in
if let document = document, document.exists {
let data = document.data()
let name = data?["name"] as? String ?? "Anonymous"
packRef.getDocuments(completion: { (snapshot, error) in
if let err = error {
debugPrint("Error fetchings docs: \(err)")
} else {
guard let snap = snapshot else { return }
for document in snap.documents {
let data = document.data()
let dogUid = data["dogUid"] as? String ?? "No dogUid"
let dogName = data["dogName"] as? String ?? "No dogName"
let dogBreed = data["dogBreed"] as? String ?? "No dogBreed"
let dogBorn = data["dogBorn"] as? String ?? "No dogBorn"
let dogProfileImageURL = data["dogProfileImageURL"] as? String ?? "No dogProfileImageURL"
let newDoggo = Doggo(dogUid: dogUid, dogName: dogName, dogBreed: dogBreed, dogBorn: dogBorn, dogProfileImageURL: dogProfileImageURL)
self.doggos.append(newDoggo)
print(newDoggo)
}
}
self.user = User(uid: userUid, name: name, pack: self.doggos)
print(self.user)
self.configureHomeController()
self.configureMenuController()
})
} else {
print("Document does not exist")
}
}
It appears to work the way I'd like it to, but I don't want to run into issues down the line as it's quite foundational to the rest of the app.

How to Update CollectionView Model with Firebase?

I am trying to intitialize my Collection View Model which holds a list of [Users] with a firebase snap that holds data.
Here is the Collection View Model code:
typealias JSON = [String:Any]
class HomeDataSource: Datasource {
var users: [User]
init?(with snapshot:DataSnapshot) {
var users = [User]()
guard let snapDict = snapshot.value as? [String: [String:Any]] else {return nil}
for snap in snapDict {
guard let user = User(dict: snap.value) else {continue}
users.append(user)
}
self.users = users
}
}
User Model:
struct User {
let name: String
let username: String
init?(dict: JSON) {
guard let name = dict["name"] as? String,
let email = dict["email"] as? String
else {return nil}
self.name = name
self.username = email
}
}
Firebase Snap:
Snap (users) {
8CVeHMNHI6hZAWj1zhGHEjPwYYz1 = {
email = "Silviu#isidors.sjsj";
name = Bshdjdj;
};
9CuqgR4Es7TOPPJQEpSnQXlfYnm1 = {
email = "Test#silviu.com";
name = "Test#silviu.com";
};
DBqGWlpdJKME570euqUz2rqI5Z83 = {
email = "Test#test.test";
name = Test;
};
}
Fetch Function:
func fetchUser() {
let ref = Database.database().reference().child("users")
ref.observe(.childAdded, with: { (snapshot) in
let user = User(dict: snapshot.value as! JSON)
self.users.append(user!)
print(self.users)
let new = HomeDataSource(with: snapshot)
print(new)
DispatchQueue.main.async(execute: {
self.datasource = new
self.collectionView?.reloadData()
})
}, withCancel: nil)
}
Right now, I am getting an array of Users from Firebase, however my collection view won't update.
My question is how should I update my Collection View Model and Fetching Function so it can fetch data from Firebase and Populate the Collection View Correctly?
So the problem was the node I was targeting. Removed "child("users")" form fetching function and targeted the whole users node with uids. Then I was looping the snapshot.value while I casted it in [String:[String:Any]], because each snapshot.valuelooked like this (key: "vijwUkzAlbgcqjAammfy0JuVMB33", value: ["name": Silviu, "email": Office#isidors.com]) Finally, I updated the HomeDataShource Class like this:
class HomeDataSource: Datasource {
var users: [User]
init(with snapshot:DataSnapshot) {
var users = [User]()
let snapDict = snapshot.value as? [String:[String:Any]]
for snap in snapDict! {
guard let user = User(snap: snap.value) else {continue}
users.append(user)
}
self.users = users
}

How to get to a specifec node in firebase database real-time

I got some messages key that was created by ChildByAutoID i am trying to access them or make the code read this keys to use this key somewhere else to get the some data from using this keys from firebase database
I tried to observe the UID of user to get keys but i can't get access to them as in code it show me the snap is the UID of user while iam trying to read nodes under the UID
in chat Controller
func sendMessage() {
let currentUserID = Auth.auth().currentUser?.uid
let databaseRef = Database.database().reference().child("messages")
let timestamp = Date.timeIntervalSinceReferenceDate
let text = typingMessageText.text as AnyObject
let receiverid = user?.userid as AnyObject
let senderid = currentUserID as AnyObject
let time = timestamp as AnyObject
let value: [String:AnyObject] = ["text": text, "receiverid": receiverid, "senderid": senderid, "timestamp": time]
let childref = databaseRef.childByAutoId()
childref.updateChildValues(value) { (error, myRef) in
print(myRef.key as Any)
let messageID = myRef.key
let mnm = [messageID : 1]
let userMessageRef = Database.database().reference().child("usersmesssages").child(currentUserID!)
userMessageRef.updateChildValues(mnm)
}
}
Observe function in tableview controller
func observeMessages(){
let currentUserID = Auth.auth().currentUser?.uid
let newDB = Database.database().reference().child("usersmesssages").child(currentUserID!)
newDB.observe(.value) { (DataSnapshot) in
let key = DataSnapshot.key
print("the Key is \(DataSnapshot)")
let dbRef = Database.database().reference().child("messages").child(key)
dbRef.observe(.childAdded, with: { (snap) in
print("thesnap is \(snap)")
if let dictinoary = snap.value as? [String: AnyObject] {
guard let receiverid = dictinoary["receiverid"] ,let senderid = dictinoary["senderid"], let text = dictinoary["text"], let time = dictinoary["timestamp"] else {
return
}
let messageValues = Message.init(text: text as? String, receiverid: receiverid as? String, senderid: senderid as? String, timestamp: time as? TimeInterval)
self.messages.append(messageValues)
dbRef.keepSynced(true)
self.ChatRoomTable.reloadData()
}
})
}
}
UPDATE
print("the data is \(DataSnapshot)")
Result from it
the data is Snap (KxTbutCjzGQmIIb2OCGHrCyLNS53) {
"-LVx10-pBVxXTN-p88pT" = 1;
"-LVx10rtB0SL0y_mn4FU" = 1;
"-LVx4XosKZhkUDPgq0TI" = 1;
"-LVx4YT3NqYi1Tj12QFj" = 1;
"-LVx4_e8_OKwUrpAR_BM" = 1;
"-LVy2TEHGZD99ALhutbX" = 1;
"-LVy2dZB_mSIicC-qcSA" = 1;
"-LVy2xkg0oTT6bLbdC4T" = 1;
"-LVy3H6a__Tm_DKnM639" = 1;
}
How to access this nodes that (= 1) it self or save it to variables to use it.

Updating child in firebase not working as expected

I am trying to save data into firebase, by first generating a child using .childByAutoId() and then update the child with the necessary data. But it doesn't seem to work as expected.
The structure I am trying to achieve is
events
attendees
-L0P1D5arR0OkBf8h
userEmail: "user#user.com"
userName: "User name"
userPhone: "0864567182"
Here's what I have done so far:
guard let fee = events?["eventFee"] else {
return
}
guard let key = events?["eventKey"] else {
return
}
guard let eventTitle = events?["title"] else {
return
}
if fee == "0" {
var values = [String: String]()
self.ref = Database.database().reference()
let attendeekey = ref.child("events").child(key).child("attendees").childByAutoId().key
let userDetails = UserDetails()
for user in userDetails.currentUserDetails {
guard let userEmail = user.email else {
return
}
guard let firstName = user.firstName, let lastName = user.lastName else {
return
}
guard let userPhone = user.phoneNo else {
return
}
let userName = "\(firstName) \(lastName)"
values = ["userEmail": userEmail, "userName": userName, "userPhone": userPhone as! String]
}
ref.updateChildValues(["events/\(key)/attendees/\(attendeekey)": values], withCompletionBlock: {
(err, ref) in
if err != nil {
self.displayAlertMessage(message: err as! String, title: "Oops!")
//print(err ?? "An error occured")
return
}
let message = "You have successfully registered for \(eventTitle)"
self.displayAlertMessage(message: message, title: "Success!")
})
}
Is anything wrong with my approach?