This question already has answers here:
How to restructure object of NSDictionaries
(2 answers)
Closed 7 years ago.
I'm querying an object of type NSArray called messages from my backend on parse.com that looks like this:
self.messages = (
"<lean: 0x7fcf98665140, objectId: vglE1UJ5KI, localId: (null)> {\n messageBody = Jj;\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424991590106.210938\";\n}",
"<lean: 0x7fcf98667940, objectId: rgBFYBMKlU, localId: (null)> {\n messageBody = \"test 3 from ian\";\n recipientId = XvvxETqjph;\n senderId = Hoy7UjLzOh;\n timestamp = \"1424631667110.638184\";\n}",
"<lean: 0x7fcf98667f30, objectId: hB5uhwsYsu, localId: (null)> {\n messageBody = \"test 2 from user1\";\n recipientId = XvvxETqjph;\n senderId = VQzxWbDnal;\n timestamp = \"1424630904935.162109\";\n}",
"<lean: 0x7fcf986685b0, objectId: dOe2B9oq5b, localId: (null)> {\n messageBody = \"test 1\";\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424630808309.478027\";\n}"
)
So its basically an array of dictionary objects. How do I reformat this as a normal array of dictionaries that looks like this:
self.messages = (
"{\n objectId: vglE1UJ5KI;\n messageBody = Jj;\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424991590106.210938\";\n}",
"{\n objectId: rgBFYBMKlU;\n messageBody = \"test 3 from ian\";\n recipientId = XvvxETqjph;\n senderId = Hoy7UjLzOh;\n timestamp = \"1424631667110.638184\";\n}",
"{\n objectId: hB5uhwsYsu;\n messageBody = \"test 2 from user1\";\n recipientId = XvvxETqjph;\n senderId = VQzxWbDnal;\n timestamp = \"1424630904935.162109\";\n}",
"{\n objectId: dOe2B9oq5b;\n messageBody = \"test 1\";\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424630808309.478027\";\n}"
)
The PFObject returned from parse is very much like a dictionary, insofar as it responds to allKeys and objectForKey: and setObject:forKey:, and so on. I've seen several questioners on SO confused by the way PFObject implements description and therefore how it prints on the console, making it look less like a dictionary than it perhaps should.
Anyway, if for some reason one really must have an NSArray of NSDictionaries, rather than an NSArray of dictionary-like objects, then they could employ code like this:
- (NSDictionary *)dictionaryFromPFObject:(PFObject *)pfObject {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
for (NSString *key in [pfObject allKeys]) {
dictionary[key] = [pfObject objectForKey:key];
}
return dictionary;
}
... and call it from a find completion block like this:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *array = [NSMutableArray array];
for (PFObject *pfObject in objects) {
[array addObject:[self dictionaryFromPFObject:pfObject]];
}
}
}];
Related
I am attempting to retrieve a PFUser which is inside a NSDictionary however I am not able to retrieve any data when I run my code. The PFUser in the provided dictionary is the User key. Here is my output:
// My dictionary
{
hours = "10 Hours";
location = j;
notes = h;
title = j;
user = "<PFUser: 0x7fea4d578d90, objectId: h1WOITDkrF, localId: (null)> {\n email = \"XXXXX#yahoo.com\";\n fullName = Pradyumn;\n username = Prnk281;\n }";
}
// Should be displaying the PFUser objectId displays null
2015-12-03 22:11:24.774 XXXXX[16176:816409] User ID: (null)
Here is my code as attempt to retrieve the objectId from within the PFUser,
-(void)savePressed:(UIBarButtonItem * __unused)button
{
NSArray * validationErrors = [self formValidationErrors];
if (validationErrors.count > 0){
[self showFormValidationError:[validationErrors firstObject]];
return;
}
NSLog(#"FormValues: %#",self.formValues);
PFUser *selectedUser = [self.formValues objectForKey:#"user"];
NSLog(#"User ID: %#", [selectedUser objectForKey:#"objectId"]);
[self.tableView endEditing:YES];
}
When you make a query to get this data just add one line in the query.
[query includeKey:#"YOUR COLUMN NAME"];
You will get all the details of user in your current dictionary try this out.
I managed to solve my answer by following the two given comments.
First I checked to see if my selectedUser was a available value, which it was:
NSLog(#"Selected user : %#",selectedUser);
Then I did what #paulw11 said and used selectedUser.objectId
In the docs https://www.parse.com/docs/ios/guide#relations-using-pointers
it says that in the example provided you can find the User who created the game
// say we have a Game object
PFObject *game = ...
// getting the user who created the Game
PFUser *createdBy = [game objectForKey:#"createdBy"];
But when I use the exact syntax since I want to populate the pointer in my "user" column
PFUser *user = [PFUser currentUser];
NSString *username = user.username;
// Inside my queryForTable method so PFObject is returned in
// tableView:cellForRowAtIndexPath:object
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"fromUser = %#", user];
PFQuery *query = [PFQuery queryWithClassName:#"Activities" predicate:predicate];
// Inside tableView:cellForRowAtIndexPath:object
PFUser *createdBy = [object objectForKey:#"user"];
NSLog(#"User to user ---%#", createdBy);
But All I get back is
User to user ---<PFUser: 0x7ff9024da860, objectId: aOisP569e3, localId: (null)> {
// Nothing here
}
If I'm understanding correctly, am I also supposed to get back username, email etc in my user object?
---UPDATE 1---
looking at the Anypic app provided by parse it should return something like this
<PFUser: 0x7f7ff9fafc00, objectId: LfADtx1K2J, localId: (null)> {
// Stuff appears here
displayName = "poopiu";
facebookId = 130941340571204;
profilePictureMedium = "<PFFile: 0x7f7ff9faf500>";
profilePictureSmall = "<PFFile: 0x7f7ff9faf7f0>";
username = I34MBM3WYSB5tjWIIvUvhH5fq;
}
but mine is empty even though I have a column called username that isn't undefined so I should get that inside my PFUser object
--UPDATE 2--
Here's what I get back from logging object like so...
NSLog(#"Object---%#", object);
<Activities: 0x7fbbebf42d20, objectId: rDwYI5Inuk, localId: (null)> {
user = "<PFUser: 0x7fbbee1367e0, objectId: SFL0kVZ17x>";
status = 0;
>
Add the following method call after you instantiated your query.
[query includeKey: "user"];
By default, queries do not grab information past the immediate object that was queried.
Are you sure your user isn't nil? According to the docs you must be logged in for currentUser to return a user object.
[createdBy fetch];
NSLog(#"User to user ---%#", createdBy);
Try this hope this will help
In some condition i need current user and other user.I am getting current user data fine, but i dont know how to get other user data.my code is
PFUser *user1 = [PFUser currentUser];
PFObject *user2 = [PFObject objectWithoutDataWithClassName:#"_User" objectId:Objid];
my output for user1 is
<PFUser: 0x7fd3427923f0, objectId: a1P2ZZf46E, localId: (null)> {
email = "xxxx#gmail.com";
fullname = xxxx;
picture = "<PFFile: 0x7fd342791950>";
thumbnail = "<PFFile: 0x7fd342791ee0>";
username = "xxxx#gmail.com";
}
but for user2 is
<PFUser: 0x7fd3448b8bd0, objectId: XluNx9rZdV, localId: (null)> {
}
Because you are using objectWithoutDataWithClassName which will return you back PFObject with objectId only. So, if you want to get the full object by its objectId, you can use + (PF_NULLABLE PFObject *)getObjectOfClass:(NSString *)objectClass objectId:(NSString *)objectId to get back the object like so:
[PFQuery getObjectOfClass:#"_User" objectId:Objid];
You may try something like this:
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" equalTo:Objid];
NSArray *user2 = [query findObjects];
PFuserProfile = [user2 firstObject];
In my debugger this is how my log statement is printing my messages object:
self.messages = (
"<lean: 0x7fcf98665140, objectId: vglE1UJ5KI, localId: (null)> {\n messageBody = Jj;\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424991590106.210938\";\n}",
"<lean: 0x7fcf98667940, objectId: rgBFYBMKlU, localId: (null)> {\n messageBody = \"test 3 from ian\";\n recipientId = XvvxETqjph;\n senderId = Hoy7UjLzOh;\n timestamp = \"1424631667110.638184\";\n}",
"<lean: 0x7fcf98667f30, objectId: hB5uhwsYsu, localId: (null)> {\n messageBody = \"test 2 from user1\";\n recipientId = XvvxETqjph;\n senderId = VQzxWbDnal;\n timestamp = \"1424630904935.162109\";\n}",
"<lean: 0x7fcf986685b0, objectId: dOe2B9oq5b, localId: (null)> {\n messageBody = \"test 1\";\n recipientId = XvvxETqjph;\n senderId = XvvxETqjph;\n timestamp = \"1424630808309.478027\";\n}"
)
what exactly is this? It looks like an object of dictionaries but the objectId and localId variables are outside of the curly braces so im not sure.
How do I restructure this so that I can have each individual dictionary by itself?
Im getting this data from my backend on parse.com:
-(void)viewWillAppear:(BOOL)animated{
NSString *userId = [[PFUser currentUser] objectId];
PFQuery *query = [PFQuery queryWithClassName:#"lean"];
[query whereKey:#"recipientId" equalTo:userId];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
// We found messages!
masterMessages = (NSDictionary *)objects;
NSLog(#"self.messages = %#", masterMessages);
[self.tableView reloadData];
}
}];
}
this is a simple NSArray which contains objects of type named lean. you can get the needed object by its index
UPDATE:
I can't be sure of course. I have no idea about lean's structure. But most likely it contains field (and I assume it must be a property) named messageBody. If it is really so then you can do the following:
NSMutableArray* messagesBySenderName = [NSMutableArray new];
for (id lean in objects)
{
NSDictionary *messageBody = [lean valueForKeyPath:#"messageBody"];
if ([lean[#"senderId"] isEqualToString:#"Hoy7UjLzOh"])
{
[messagesBySenderName addObject:messageBody];
}
}
Again - it is only an assumption. In no case I can guarantee it will work
They are PFObjects (from the parse.com framework), and PFObject implements description in this particular way. PFObjects implement a dictionary-like interface that is fully described here.
With due respect to others, it is overly general to type them as id, and to use KVO to access their properties. Moreover, messageBody appears to be a column of type string. Treating as a dictionary will be unproductive.
PFObjects should be treated this way:
for (PFObject *pfObject in objects) {
NSString *objectId = [pfObject objectId];
NSDate *createdAt = [pfObject createdAt];
NSString *messageBody = [pfObject objectForKey:#"messageBody"];
NSString *senderId = [pfObject objectForKey:#"senderId"];
// and so on
NSLog(#"This object has id %# created at %#, senderId %#", objectId, createdAt, senderId);
}
I'm aware of your other recent SO question regarding how to derive and array of senderIds from this array. Extracting senderId ought to be obvious from this code, but (a) you probably don't need a new array based on your UI need (a table of conversations), and (b) I think you're actually looking for senderName, and that might mean a substantial change to how you've implemented relationships between parse objects.
I'll try to answer further over on that other question, but this one is clearly related.
This question already has answers here:
Sorting NSArray of dictionaries by value of a key in the dictionaries
(11 answers)
Closed 9 years ago.
Suppose I would like to sort array by "firstName" key.
Example
Array = (
{
People1 = {
firstName = #"Jack Adam";
email = #"adam#gmail.com";
};
Address = {
cityCode = #"TH";
};
},
People2 = {
firstName = #"Jack DAm";
email = #"dam#gmail.com";
};
Address = {
city = #"TH";
};
);
user Sort Comparator
NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:^(NSDictionary *a, NSDictionary *b) {
return [a[#"People"][#"firstname"] compare:b[#"People"][#"firstname"]];
}];
But Your Key is inconsistency ...
I Think that data should be
Array = (
{
People = {
firstName = #"Jack Adam";
email = #"adam#gmail.com";
};
Address = {
cityCode = #"TH";
};
},
People = {
firstName = #"Jack DAm";
email = #"dam#gmail.com";
};
Address = {
city = #"TH";
};
);
Using blocks and modern Objective-C syntax:
NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:^(NSDictionary *first, NSDictionary *second) {
return [first[#"Person"] compare:second[#"Person"]];
}];
Using NSSortDescriptor:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"firstName" ascending:YES];
myArray=[stories sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];
temp = [stories copy]; //temp is NSMutableArray
myArray is the array you want to sort.
First,you should implement a compare-method for your object.
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingSelector:#selector(compare:)];
As you replied in a comment, the first dictionary key is "Person1" in all array elements.
Then "Person1.firstName" is the key path that gives the first name of each array
element. This key path can be used in a sort descriptor:
NSArray *array = ... // your array
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"Person1.firstName" ascending:YES];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:#[sort]];