Firebase: How to get User.uid? - swift

I'm using Firebaseauth to manage users and data for my iOS app. The users can log in, and their userinfo is stored correct in the database.
But when I try to get the users to write to the database in a different viewController, using this string:
self.ref.child("users").child(user.uid).setValue(["username": username])
The thrown error is
Type user has no member .uid
That makes sense I guess, since I haven't created the variable. But I can't figure out how to declare it?

This is how you get the user's uid:
let userID = Auth.auth().currentUser!.uid
UPDATE: Since this answer is getting upvotes, make sure you prevent your app from crashing by using guards:
guard let userID = Auth.auth().currentUser?.uid else { return }

You might want to use a guard, as a force unwrap might break your app if a user isn’t signed in.
guard let userID = Auth.auth().currentUser?.uid else { return }

FIRAuth has actually been renamed to Auth. So, as per the latest changes, it will be
let userID = Auth.auth().currentUser!.uid
Edit.
As pointed out in comments, A force unwrap may crash the app.
guard let userID = Auth.auth().currentUser?.uid else { return }

Related

Firebase realtime database query doesn't get new data until app reinstalled

In my app on sign up I'm checking if username is already taken.
I install the app, go to sign up, check if the username is free and everything works fine. If username is taken it tells me that.
But then when I created the account and trying to create another one with the same username, for some reason this username cant be found in database, even tho it's there.
Here is the code I use:
func singleObserveUser(withUsername username: String, completion: #escaping (UserModel) -> Void, onError: #escaping (String) -> Void) {
let queryUsername = username.lowercased().trimmingCharacters(in: .whitespaces)
usersRef.queryOrdered(byChild: Constants.UserData.UsernameLowercased).queryEqual(toValue: queryUsername).observeSingleEvent(of: .value) { (snapshot) in
if let _ = snapshot.value as? NSNull {
onError("No userdata found")
} else {
if let dict = snapshot.value as? [String: Any] {
let user = UserModel.transformDataToUser(dict: dict, id: snapshot.key)
completion(user)
} else {
onError("No userdata found")
}
}
}
}
If I restart app - everything is still the same.
If I delete app and install it again - everything works fine.
Seams like Firebase save some data on phone.
Thank you for your help!
If you have disk persistence enabled (the default on iOS and Android), the client stores data it has recently seen to allow it faster lookup later, and observeSingleEvent(of returns the value from that cache indeed.
If you want to ensure you have the latest value from the server, use getData instead as shown in the documentation on getting data once. Also check out Firebase Offline Capabilities and addListenerForSingleValueEvent for a longer explanation of the behavior.

How to add data to Firestore Cloud without hardcoding user collection document id in Swift

Initially I created a collection Users in my Firestore Cloud database with a subcollection Wishlist.
To add to the wishlist, I hardcoded the following to test it works:
let db = Firestore.firestore()
db.collection("users/JldiJEK5i84DZWhlTFg6/wishlist").addDocument(data: ["plant" : plants[0], "image" : plants[1]])
}
Once button is tapped, the plant is sent to that particular User's wishlist and it works -- I can see this being added to the database.
How do I...
I cannot figure out in the documentation how not to hardcode the document id. I would like it to just add the plant for every user signed in?
Get the current user:
let user = Auth.auth.currentUser
if let user = user {
_ = user.id
}
Then:
let db = Firestore.firestore()
db.collection("users/\(user?.uid ?? "error")").addDocument(data: ["plant" : plants[0], "image" : plants[1]])
This works for me when dealing with people/customers, I just have an error document in Firestore, but your user is more than likely never going to be nil if they log in or create an account.
Edit:
Just to be safe, this is probably better and will avoid unnecessary writes to Firestore when there's an error (saving money)
guard let currentUser = Auth.auth().currentUser {
print("handle the error")
return
}
let uid = currentUser.uid
...

Swift saving new comments using CloudKit

I'm trying to make an app which stores a user's comment on CloudKit and then shows it to the other users. User simply enters his/her comment on a text field and clicks on a submit button to submit his/her comment (just like a restaurant app). However, I can't seem to find the correct way no matter what I try. Here is my code, I'd be very glad for any help as I've been stuck on this problem for some time now. Thank you very much in advance!
#IBAction func OnSubmitTouched(_ sender: UIButton) {
if (textField.text != ""){
let newComment = CKRecord(recordType: "Users")
let publicDB = CKContainer.default().publicCloudDatabase
newComment.setValue(textField.text!, forKey: "comment")
publicDB.save(newComment){
rec ,err in
if let error = err {
print(err.debugDescription)
return
}
publicDB.fetch(withRecordID: newComment.recordID){
rec, err in
print(rec!["comment"]!)
return
}
}
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "comment", predicate: predicate)
let operation = CKQueryOperation(query: query)
var commentRecords: [CKRecord] = []
operation.recordFetchedBlock = { record in
commentRecords.append(record)
}
operation.queryCompletionBlock = { cursor, error in
print(commentRecords)
}
CKContainer.default().publicCloudDatabase.add(operation)
}
}
You are getting a permission error because Users is a protected record type that CloudKit creates automatically for users of your app. You should name it something else and then it should work.
For example, you could make a Comment record type. This might need a field that references the current user. You can get the current userID with:
CKContainer fetchUserRecordIDWithCompletionHandler:
Here is the Apple documentation for this method.
It is also possible to use the Users record type, but you would have to find the existing userID from CloudKit as above then build a record around that.
See also this answer.

When retrieving data from Firebase Database, <null> is returned: "Snap (...) <null>"

I'm a relatively new Swift programmer and am using Firebase for the first time so please excuse any misunderstandings I may have and my lack of knowledge about terminology.
I am attempting to retrieve data about a user that is stored in a database (email and username).
The code successfully finds the userID in the database. The userID is then used in order to navigate into the directory containing the username and email. It stores those values in snapshot.
For some reason, when snapshot is printed, it shows the userID but the contents of the directory (username and password) are shown as <null>. I am certain that the directory I am attempting to access and retrieve data from exists and is not empty (it contains a username and email). I wantsnapshot to store the username and email, but printing shows that it is not doing so correctly and I cannot figure out why.
here is my code block:
func checkIfUserIsLoggedIn() {
if Auth.auth().currentUser?.uid == nil {
perform(#selector(handleLogout), with: nil, afterDelay: 0)
} else {
let uid = Auth.auth().currentUser?.uid;
Database.database().reference().child("Users").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let dictionary = snapshot.value as?[String:AnyObject] {
self.userLabel.text = dictionary["name"] as? String
}
}, withCancel: nil)
}
}
and here is what is being printed to the console:
Snap (ywU56lTAUhRpl3csQGI8W8WmQRf1) <null>
Here is the database entry I am attempting to reach and log to snapshot:
I'm a new Stack Overflow user and don't have enough experience on the site to be allowed to embed images in posts, so this is the external link
Thanks for reading, any help would be much appreciated!!
Your reference in Firebase is to "users", but you are using .child("Users") in your code. Make sure your lookup matches case to your node. I find it best to create a reference to that node and use it for writing to and reading from.
let usersRef = Database.Database().reference().child("users")
Snap (ywU56lTAUhRpl3csQGI8W8WmQRf1) <null> the portion in parenthesis refers to the end node of what you are trying to observe. In this case it refers to uid!.
if u want to get username or email then you make first the model class for
Example:-
class User: NSObject {
var name: String?
var email: String?
}
then user firebase methed observeSingleEvent
FIRDatabase.database().reference().child("user").child(uid).observeSingleEvent(of: .value, with: { (snapShot) in
if let dictionary = snapShot.value as? [String: Any]{
// self.navigationItem.title = dictionary["name"] as? String
let user = User()
user.setValuesForKeys(dictionary)
self.setUpNavigationBarWithUser(user: user)
}
})`
if it is not finding your asking values, you are asking wrong directory. check firebase db child name it must be exactly like in your code ("Users")

How to access custom user table columns from Parse.com

How should I access columns that I've added to the User table when I have a currentUser object?
I have a PFUser.currentUser() and I want to access the nickname column that I added via the web interface.
Can I use the currentUser to get the data e.g.:
var nickname = PFUser.currentUser()["nickname"] as String
Or do I have to use a user query? e.g.:
var query = PFUser.query()
query.whereKey("username", equalTo:PFUser.currentUser().username)
var user = query.findObjects().first as PFUser
var nickname = user["nickname"]
If you added date to the column locally, then you have to use the first way as you wrote, or if you added date in the browser, or uploaded to parse.com some way, you have to use the second way.
I would like to give my two cents too. First of all, Daniel was right in saying that if you added the date in the browser or uploaded it to parse.com, you need to use the second way. This is an updated answer with iOS 9 and Xcode 7.2:
var query = PFUser.query()
query!.whereKey("username", equalTo:PFUser.currentUser()!.username!)
do {
user = try query!.findObjects().first as! PFUser
} catch {
print("Error finding user")
}
if user?["rankNumber"] as? Int == nil {
user!["rankNumber"] = 0
user!.saveInBackground()
} else {
print(user!["rankNumber"] as! Int)
}
If I did it any other way, xcode would give me an error saying "failing to unwrap optional". I hope this can help someone!