I'm trying to retrieve data from the current User's row and display it in their profile. (Data such as firstName, lastName, email, postalCode etc - Which are all in separate columns). I can retrieve all the data by using:
PFUser *currentUser = [PFUser currentUser];
if (currentUser != nil) {
NSLog(#"Current user: %#", currentUser.username);
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:currentUser.username];
NSArray *data = [query getObjects];
NSLog(#"%#", data);
}
but I don't think I can separate the data by this method. It only displays everything at once. I would like it to assign to separate labels to display firstName, lastName etc.
Whatever method you use to query for the currentUser, you (hopefully) will be returning one PFObject. Since the PFObject is essentially a Dictionary, you just than have all of the data for that user with access to object's Key-Value pairs.
I prefect KVC rather than just calling methods on the currentUser class because it's possible you have custom fields that can't easily be queried for.
Below is my solution to query for currentUser and set up their profile.
ProfileVC.h
#property (nonatomic, strong) PFUser *profileToSet;
ProfileVC.m
-(void)setProfile{
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" equalTo:[[PFUser currentUser]objectId]];
[query findObjectsInBackgroundWithBlock:^(NSArray * objects, NSError * _Nullable error) {
if (error) {
NSLog(#"error: %#",error);
} else {
self.profileToSet = [objects firstObject];
// Do the rest of the setup with the profileToSet PFUser PFObject.
}
}];
What you're doing there is printing out the full array of results from your query, which is why it looks like all the fields are being put together (when they're not really). If you want to retrieve/refresh the data from Parse for the current user there's a better way. Use fetch.
PFUser *currentUser = [PFUser currentUser];
if (currentUser != nil) {
NSLog(#"Current user: %#", currentUser.username);
[currentUser fetch];
// Now your currentUser will be refreshed...
NSLog(#"First: %#, postcode: %#", currentUser[#"firstName"], currentUser[#"postalCode"]); // Assuming those keys exist.
}
It'll ensure that only the current user is returned, in a simpler way than running a PFQuery directly. You don't need to check the array length, or grab the first object out.
As noted in comments, you should look at using fetchInBackgroundWithBlock: as it'll (1) not block and (2) give you an error if something goes wrong.
Related
Code that was previously working is now failing...
I have extracted the following lines from my app to show the problem
PFQuery *query = [PFQuery queryWithClassName:#"EBInspection"];
[query setLimit:1000];
[query whereKey:#"ParentID" equalTo:#"OdP1ZnYHib"];
NSLog(#"Count = %i", [query findObjects].count);
These lines find 34 matching rows in the EBInspection table, however there are 86 rows, which I have confirmed using the Parse dashboard and setting a query. I have also written the following code to test all rows, and it returns 86!!
PFQuery *query = [PFQuery queryWithClassName:#"EBInspection"];
[query setLimit:1000];
[query setSkip:2000];
int nIns = 0;
for (PFObject *obj in [query findObjects]) {
if ([obj[#"ParentID"] isEqualToString:#"OdP1ZnYHib"]) nIns += 1;
}
NSLog(#"count= %i",nIns);
Strange indeed. Looks like some kind of data corruption that messes up the query. Any suggestions are much appreciated.
Use countObjectsInBackgroundWithBlock instead of findObjects and then counting the results yourself. Try the following
Objective-C
PFQuery *query = [PFQuery queryWithClassName:#"GameScore"];
[query whereKey:#"playername" equalTo:#"Sean Plott"];
[query countObjectsInBackgroundWithBlock:^(int count, NSError *error) {
if (!error) {
// The count request succeeded. Log the count
NSLog(#"Sean has played %d games", count);
} else {
// The request failed
}
}];
Swift
var query = PFQuery(className:"GameScore")
query.whereKey("playerName", equalTo:"Sean Plott")
query.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError?) -> Void in
if error == nil {
print("Sean has played \(count) games")
}
}
For more information on count operations see my detailed explanation here
I have already set up push notifications through Parse and Apple, and I can't seem to find a straight forward way to send push notifications to another user.
For my case, I want to send a user a notification when a user sends a friend request to them. here is the code I am using to save to request to the server:
//get current user
PFQuery *query2 = [PFUser query];
[query2 whereKey:#"username" equalTo:pendingFriendName];
PFUser *userTo = (PFUser *)[query2 getFirstObject];
PFQuery *query = [PFQuery queryWithClassName:#"Follow"];
[query whereKey:#"from" equalTo:[PFUser currentUser]];
// execute the query
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
PFObject *follow = [PFObject objectWithClassName:#"Follow"];
[follow setObject:[PFUser currentUser] forKey:#"from"];
[follow setObject:userTo forKey:#"to"];
[follow saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(succeeded)
{
NSLog(#"success!");
[friendAddedLabel setText:#"Friend Added!"];
}
else
{
NSLog(#"error");
}
}];
}
}];
In addition, is there a way to send a direct reference of the user who sent the request to the user who received the friend request so that it can quickly have the information accessible when the user taps the notifcation instead of going through another query?
First, you have to store the current user into Installation class then send push notification using PFInstallation Query and PFPush.
//save the user into installtion class.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
if ([PFUser currentUser].objectId)
{
currentInstallation[#"user"] = [PFUser currentUser];
currentInstallation.channels = #[[NSString stringWithFormat:#"user_%#",[PFUser currentUser].objectId]];
NSLog(#"Saving Installation channel = %#",currentInstallation.channels);
[currentInstallation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
NSLog(#"Current installation updated: Error: %#",error);
}];
}
//Then send push notification to particular user.
PFQuery *queryInstallation = [PFInstallation query];
[queryInstallation whereKey:#"user" equalTo:user];
PFPush *push = [[PFPush alloc] init];
[push setQuery:queryInstallation];
NSDictionary * dic = #{#"alert" : text,#"badge" : #"Increment" , #"sender" : [PFUser currentUser].objectId ,#"MediaId" : mediaObject.objectId};
[push setData:dic];
[push sendPushInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error != nil && !succeeded)
{
NSLog(#"SendPushNotification send error.");
}
else
{
NSLog(#"SendPushNotification send success.");
}
}];
I have the user's unique ID, but I'm not sure how to retrieve the username from the Parse Data Base with this info. I'm storing the ID's in an array, and I've tried to loop through it but i don't know where to go from there. Any help would be appreciated!
Its simple here you go!
NSArray *arrayOfUsersObjectIDs = ...;
PFQuery *queryForUsers = [PFQuery queryWithClassName:#"Your_Class_Name"];
[queryForUsers whereKey:#"objectId" containedIn:arrayOfUsersObjectIDs];
[queryForUsers findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error) {
for(PFObject *objUser in objects) {
NSLog(#"User name: %#", objects[#"Key_For_Name"]);
}
}
}];
I would like to know how I can get an array with all the name of record type in my private database in Cloud Kit for read all my data ?
I save my data :
CKRecord* fav1 = [[CKRecord alloc] initWithRecordType:#"Favoris1"];
[fav1 setObject:#"Favoris 1 name"forKey:#"name"];
[fav1 setObject:#"2003 year"forKey:#"year"];
[self.privateDatabase saveRecord:fav1
completionHandler:^(CKRecord *savedState, NSError *error) {
if (error) {
NSLog(#"ERROR SAVING: %#", error);
}
else{
NSLog(#"SAVE OK");
}
}];
I read my data :
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"Favoris1" predicate:[NSPredicate predicateWithFormat:#"TRUEPREDICATE"]];
[self.privateDatabase performQuery:query
inZoneWithID:nil
completionHandler:^(NSArray *results, NSError *error)
{
if (!error)
{
NSLog(#"results query %#", results);
NSLog(#"--> %#",[[results objectAtIndex:0] objectForKey:#"name"]);
NSLog(#"--> %#",[[results objectAtIndex:0] objectForKey:#"year"]);
}
else
{
NSLog(#"FETCH ERROR: %#", error);
}
}];
I would like to save an other record with another properties like :
CKRecord* fav2 = [[CKRecord alloc] initWithRecordType:#"Favoris2"];
[fav2 setObject:#"Favoris 2 name"forKey:#"name"];
[fav2 setObject:#"2005 year"forKey:#"year"];
How can I have an array with Favoris1 and Favoris2 for read all my record after I have saved ?
in CloudKit there is no function that will return all the available recordType's from a database. You can also not query multiple recordTypes at the same time. You have to perform 2 queries. What you could do is join the resulting arrays together if you need something like that.
Since the objects are the same, it would be better if you just used 1 recordType and add an extra field that would specify your custom type (Favoris1 or Favoris2) Then you could query just the recordType and see in the returned field what custom type it is.
I am trying to update username of [PFUser currentUser].
PFUser *user = [PFUser currentUser]; user.username = #"New Username";
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (completion) {
completion(succeeded, error);
}
}];
In case, if the username already exist, save method throws an error that "Username already exists". After that, I'm trying to get the original username from [PFUser currentUser] but it returns the new username(which is already taken).
And then I'm tried to refresh the object with refreshObject
[[PFUser currentUser] refreshInBackgroundWithBlock:^(PFObject *object, NSError *error) {
NSLog(#"%#",object);
}];
This method also returns the new username, not the original username.
How to do this? Which is best way to do this?