Parse.com - email from PFUser object fetches a nil despite having value - ios

I have a query "items" object. The class has a "parent" key that points to _User object.
The query is successful and fetches 'parent' object and i am able to access some custom keys from this 'parent' object but email is returned as nil !!
below is stripped down code.
Could anyone suggest why is this happening? This was working earlier and i have not made any code change. Running Parse-server ver 2.5.3 on Heroku.
let query = PFQuery(className: "items")
query.includeKey("parent") // parent points to _User
do {
let results = try query.findObjects()
for result in results {
let parent = result["parent"] as! PFUser
let foundUser = User()
foundUser.user = parent // User.user is of PFUser type
//custom keys in _User
foundUser.name = parent["name"] as! String
foundUser.city = parent["city"] as! String
foundUser.geoLocation = parent["location_geopoint"] as! PFGeoPoint
foundUser.userAddress = parent["user_address"] as! String
//this is failing with nil eventhough there is value in Parse
foundUser.email = parent["email"] as! String
// also tried this. parent.objectId returns a valid value
foundUser.email = parent.email
}
} catch...

Got the answer here enter link description here
In 2.3.0 there was a breaking change introduced which restricted the fields returned from a query on _User. If I remember correctly, email is taken out by default and you can specify additional fields to be removed from a query result in a configuration setting. In order to retrieve email you either have to specify the master key or be the owner of that object.

Related

Firebase - updateChildValues crashes app when setting key in dictionary from constant

All I am trying to accomplish is setting the user's email string as a key in my database. My issue seems to be that the updateChildValues method crashes whenever I set the dictionary using a key that I have assigned to a constant - In this case userEmail. If I change the key to a string literal it works just fine, but that is not how I intend to structure this database node.
guard let uid = Auth.auth().currentUser?.uid, let email = Auth.auth().currentUser?.email else {
// handle
return
}
let groupId = UUID().uuidString
let userGroupIdValue = ["groupId": groupId]
let groupName = ["groupName": text]
let userEmail = [email: 1]
Database.database().reference().child("groups").child(groupId).child("memberEmails").updateChildValues(userEmail, withCompletionBlock: { (error, reference) in
// handle errors
})
If I change the userEmail dictionary to ["someText": 1] it works just fine, as do the constants userGroupIdValue and groupName. Through my troubleshooting, it seems as though this method does not like the fact that the email property in Auth.auth().currentUser? was previously an optional, even though I am using a guard statement. I have used if let statements to unwrap as well and it still crashes. Could this be a bug of sorts?
Well firebase support got back to me and it seems the issue is the email address that was unwrapped contained a "." in the string, and this character is not allowed to be used in a key in the database along with several other characters. Super frustrating but at least I have an answer.

Retrieving Data using Firebase Swift

I'm using Firebase for my Swift iOS application. I found the retrieving data tutorial on Firebase's guide a bit confusing and I am not sure why when I try to access existing values in my database results in nil values.
This is what I have so far:
usersRef.queryOrderedByChild("fbid").queryEqualToValue(userId).observeSingleEventOfType(.Value, withBlock:{ snapshot in
print("SNAPSHOT: ",snapshot.value)
Here is the result of printing snapshot.
SNAPSHOT: {
1 = {
fbid = 1;
firstName = Michelle;
friendlist = {
9 = "Kevin C";
};
lastName = C;
profilepicurl = "https:;
uid = "facebook:1";
};
}
However, the line below results in:
fatal error: unexpectedly found nil while unwrapping an Optional value
firstName = snapshot.value.objectForKey("firstName") as! String
I would like to retrieve all the values for the user (firstName, profilepicurl, friendlist, etc) and store them in variables. It seems simple but perhaps I'm missing something. Any help would be appreciated.
Your FDataSnapshot does not contain a child firstName. It only contains a child 1.
This is because you're performing a query and then asking for a value. Since a query can have many results, it returns a list of results. Even when there's only one result, it is still a list of 1.
The solution is to loop over the children:
usersRef.queryOrderedByChild("fbid")
.queryEqualToValue(userId)
.observeSingleEventOfType(.Value, withBlock:{ snapshot in
for child in snapshot.children {
print("Loading group \(child.key!)")
}
})

Firebase + swift retrieving user data

I just tried to retrieve data from firebase for my project. For example, display the facebook user name in UILabel. I store the facebook user data like this
then retrieve the data using :
let ref = Firebase(url:"https://<app-name>.firebaseio.com/users/facebook:10207213459687665/name")
ref.observeEventType(.Value, withBlock: { snapshot in
self.facebookUserName.text = snapshot.value as! String
})
It works perfectly but it is pretty stupid by retrieving user name in a specific path because that could be different facebook user login.
I'm thinking like check the user is logged in and display their name or checking the currentUser or any smarter way to do this?
I am not sure how to do that.
There are 100 different ways to do this; here's a couple
users
user_id_0
facebook_id: facebook:10207213459687665
name: Nicholas
user_id_1
facebook_id: facebook:12346578912345689
name: Frank
in the above, you would query for the facebook_id you want, which will return the node and all of the child nodes (name, address, etc). The user_id_x is a Firebase auto-generated node name (guaranteed to be distinct)
ref.queryOrderedByChild("facebook_id").queryEqualToValue("facebook:12346578912345689")
.observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
print(snapshot.value) //prints the facebook_id and Frank
})
Another option is to use your same data structure and observe that node to load the data. Keep in mind that the facebook id is the KEY of the node, not the value - .value is key:value pairs.
let ref = Firebase(url:"https://<app-name>.firebaseio.com/users")
let thisUser = ref.childByAppendingPath("facebook:12346578912345689")
ref.observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
//snapshot will contain all of the child nodes
let userName = snapshot.value.objectForKey("name")
self.facebookUserName.text = userName
})
If you just care about the users name, you could simplify your structure by using the facebook id as the key and the value would be the user name:
users
fb_10207213459687665: Nicholas
fb_12346578912345689: Frank
and retrieve with the above observe code except you would again use the .value property as in your initial question.
In this case the .value property is a string as it's the only value (there are no child nodes as in the structure you posted, which could cause issues as it could be a series a key:value pairs which would crash)
Queries add some overhead so the observe is more efficient.
I have found an answer in http://www.appcoda.com/firebase/
When we are trying to fetch the data from current user add this code below to store the uid(when creating user account)
NSUserDefaults.standardUserDefaults().setValue(result ["uid"], forKey: "uid")
assign the variable:
var CURRENT_USER_REF: Firebase {
let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String
let currentUser = Firebase(url: "\(BASE_REF)").childByAppendingPath("users").childByAppendingPath(userID)
return currentUser!
}
implement code for function:
<reference>.observeEventType(FEventType.Value, withBlock: { snapshot in
let currentUser = snapshot.value.objectForKey("username") as! String
<--your code-->
print("Username: \(currentUser)")
self.currentUsername = currentUser
}, withCancelBlock: { error in
print(error.description)
})
}
Then we could obsolete the ref in a direct path.
I had the same problem. To fix it, I created a variable that automatically references the user that's logged in:
class ViewController: UIViewController {
let UsersRef = Firebase(url:"https://<app-name>.firebaseio.com/users")
Then, under the #IBOutlet that you're trying to get the user data to show up in, write:
let LoggedInUser = UsersRef.childByAppendingPath("\(UsersRef.authData.uid)")
When you run the code, "UsersRef.authData.uid" is automatically replaced by the specific ID of the user currently logged in. This should create a direct path to the database info of the logged in user without having to manually enter the user's ID in the reference.
To retrieve data of a facebook user we can use the currentUser property of FirebaseAuth which returns a FIRUser which contains all the information about you user. After reading all the user data you can store it anywhere but for the sake of this example I have used UserDefaults.
import Firebase
func getUserInformation()
{
let user = Auth.auth().currentUser
if let user = user {
UserDefaults.standard.setValue(user.displayName!, forKey: "Username")
let uid = user.uid
UserDefaults.standard.set(uid, forKey: "user_ID")
let url = "http://graph.facebook.com/\(uid)/picture?type=square"
UserDefaults.standard.set(url, forKey: "ImageData")
}
}

Delete an objectID from an array in Parse via Button

I have an application setup so that there is an array that contains objectId's that the current user is friends/connected with. I'm attempting to create a button that deletes a single objectId from that array (kind of like an unfriend button). I'm currently passing the objectId value from a query in one view controller to another view controller that actually contains the friends profile and the delete/unfriend button. I'm getting the actual objectId as a string in the friends profile and I can print the objectId but I can't seem to figure out a way to delete this single objectId from the array.
Using PFUser.currentUser()?.removeObject() gives me an invalid field name error.
Anyone have an insight for me?
Let me know if there is more clarification needed! Thanks in advance.
Update
I have tried to also utilize this as my object code. userObjectId is received from another view controller and grabs the proper objectId of what I'd like to remove from the current users "accepted" array. This code gives me an error of "NSInternalInconsistencyException reason: Tried to save an object with a pointer to a new, unsaved object" I've tried to remove this objectId from the array in several different ways but can't seem to get it to stick. Thanks again.
var userObjectId = ""
var object: PFObject = PFObject(className: "User")
object["objectId"] = userObjectID
PFUser.currentUser()?.removeObjectsInArray([object], forKey: "accepted")
PFUser.currentUser()?.saveInBackground()
let object = PFObject(withoutDataWithClassName: "Your Class", objectId: "objectId from array")
object.deleteInBackgroundWithBlock { (success, error) -> Void in
if error == nil && success == true {
//Delete the objectId from the array
}
}
This will also remove the object from any array that holds it.

Pointers in Parse (ios)

I am trying to access an instance of a class via a pointer "Parent", and I believe I have everything right, except I have an error. The error states "Use of unresolved identifier 'object'". What am I doing wrong here?
var parentObjectId: String = String()
var query1 = PFQuery(className: "ComparablePhotos")
query1.includeKey("Parent")
if let pointer = object["Parent"] as? PFObject {
parentObjectId = object["objectId"] as! String!
}
println(parentObjectId)
You aren't actually running the query to get back the object, or more likely array of objects, which you can then access the properties of.

Resources