How do I get properties out of NSDictionary? - ios

I have a webservice that returns data to my client application in JSON. I am using TouchJson to then deserialize this data into a NSDictionary. Great. The dictionary contains a key, "results" and results contains an NSArray of objects.
These objects look like this when printed to log i.e
NSLog(#"Results Contents: %#",[resultsArray objectAtIndex:0 ]);
Outputs:
Results Contents: {
creationdate = "2011-06-29 22:03:24";
id = 1;
notes = "This is a test item";
title = "Test Item";
"users_id" = 1;
}
I can't determine what type this object is. How do I get the properties and values from this object?
Thanks!

To get the content of a NSDictionary you have to supply the key for the value that you want to retrieve. I.e:
NSString *notes = [[resultsArray objectAtIndex:0] valueForKey:#"notes"];

To test if object is an instance of class a, use one of these:
[yourObject isKindOfClass:[a class]]
[yourObject isMemberOfClass:[a class]]
To get object's class name you can use one of these:
const char* className = class_getName([yourObject class]);
NSString *className = NSStringFromClass([yourObject class]);
For an NSDictionary, you can use -allKeys to return an NSArray of dictionary keys. This will also let you know how many there are (by taking the count of the array). Once you know the type, you can call
[[resultsArray objectAtIndex:0] objectForKey:keyString];
where keyString is one of #"creationdate", #"notes", etc. However, if the class is not a subclass of NSObject, then instead use:
[[resultsArray objectAtIndex:0] valueForKey:keyString];
for example, you probably need to do this for keystring equal to #"id".

Related

How can I implement my logic properly to populate my UITableView

Sorry guys, this problem I am running into is pretty trivial. I just can't wrap my head around it so hope someone can help me. Your help is really appreciated. I am getting JSON data through NSURLConnectDelegate with a web API. I get something like this back:
(
{
id = 340
name = Vicent },
{
id = 339
name = Johny },
{
id = 338
name = Eric }
)
and I save it in a NSMutableArray as a global variable. Now, I have a NSSet of "ids". For example:
{
340, 339
}
In the numberOfRowsInSection, I return the set's count. I am trying to load only the ids in the NSSet from the array with the data saved from the webAPI, so I do something like this in cellForRowIndexPath:
for (NSNumber *num in [set allObjects]) {
NSString *newString = [[savedArray objectAtIndex:indexPath.row]
NSString *new = [num stringValue];
if ([new isEqual:newString]) {
}}
How can I just populate the ids I want?
The JSON makes it look like you have an array of dictionaries, which is a reasonable data structure to use as the data source for a table view.
It sounds like you're trying to filter your array to only include the items that are in your set. Is that right?
If so, you could write code that would create a new array containing the subset of your array elements who's ID is also in your set. There are at least a half-dozen ways to do that. One fairly simple approach would be to use the NSArray method indexesOfObjectsPassingTest. You'd pass that method a block of code that would check each array element to see if it's id object was in your set.
That would give you an NSIndexSet with the indexes of the items in your array who's ID are in your set. Then you could use the NSArray method objectsAtIndexes to get an array of only the objects that are also in the set. Something like this (Assuming that your array of dictionaries is called savedArray and your set is called allObjects:
//get the indexes of items in the array savedArray who's id appears in the set allObjects
NSIndexSet *indexes = [savedArray indexesOfObjectsPassingTest:
^(NSDictionary *obj,
NSUInteger idx,
BOOL *stop)
{
return [allObjects member: obj[#"id"]] != nil;
}
];
//Now build an (immutable) array of just the objects who's ID are in the set
NSArray *subArray = [savedArray objectsAtIndexes: indexes];
The array subArray created above is immutable. If you need a mutable array you would need to make a mutable copy, which is a one-line change.
Disclaimer: I still struggle a little with block syntax, so the above might not be exactly correct, but it gives you the general idea.

Objective-C parse json to list of object

I need to parse a json string to a NSMutableArray... I did it as follows:
JsonString = "{
"list":[
{
"IDI":{
"IDI_ID":1
},
"PAR_VPARAM":"param1",
"PAR_VALUE":"value1"
},
{
"IDI":{
"IDI_ID":2
},
"PAR_VPARAM":"param2",
"PAR_VALUE":"value2"
},
{
"IDI":{
"IDI_ID":3
},
"PAR_VPARAM":"param3",
"PAR_VVALUE":"value3"
}
]
}";
NSData *data = [JsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&err];
NSMutableArray *resultArray = [json objectForKeyedSubscript:#"list"];
I have an object called PARAMETERS, and it has the same structure of a single item of JSON: "list". When i parse it, it works, the problem is in the object inside of each item in the json: "IDI", always parse with null value.
for(NSObject *obj in resultArray){
Parameters *paritem = (Parameters *)obj;
int test = paritem.IDI.IDI_ID; //Error here!
}
How can i do it?
NSJSONSerialization won't map your JSON data to your custom class. It will provide NSString, NSNumber, NSDictionary, and NSArray objects (or their mutable counterparts, if you specify the right NSJSONReadingOptions).
If you want to map this data to your Parameters class, you have to provide that logic yourself. You cannot simply cast NSDictionary.
for(NSObject *obj in resultArray){
Parameters *paritem = [[Parameters alloc] init];
paritem.PAR_VPARAM = obj[#"PAR_VPARAM"];
paritem.PAR_VALUE = obj[#"PAR_VALUE"];
// To capture the IDI property, you will either have to
// define a new IDI class with a property named "IDI_ID",
// live with NSDictionary, or add an "IDI_ID" property
// to your Parameters class.
// In this example, I left the value as a dictionary.
paritem.IDI = obj[#"IDI"];
// Here's how you would get the IDI_ID:
NSNumber *IDI_ID = paritem.IDI[#"IDI_ID"];
}
With that out of the way, here are a couple unsolicited stylistic tips:
For variables and properties in Obj-C, lowerCamelCase is conventional. Instead of paritem.PAR_VPARAM, use parItem.parVParam (note the capital I in parItem).
Your class names should have a two- or three-letter "namespace" (much like NSString, UIView, or CGPoint). If you can't come up with a couple letters to represent this specific project, use an abbreviation of your company's name. If all else fails, use your initials.
Your parameter names are extremely vague, and somewhat redundant. Does every property really need to be prefixed with PAR_? Do you really need IDI_ID to be nested within the IDI property of your Parameters object? You could make your code much more readable by being more concise.
Here's what your code might look like if you took this advice (I'm making some assumptions of your source data):
for(NSObject *obj in resultArray){
APParameters *parItem = [[APParameters alloc] init];
parItem.parameterName = obj[#"PAR_VPARAM"];
parItem.parameterValue = obj[#"PAR_VALUE"];
// To capture the IDI property, you will either have to
// define a new IDI class with a property named "IDI_ID",
// live with NSDictionary, or add a property to your
// Parameters class which holds the IDI_ID value directly.
// In this example, I grabbed the IDI_ID value directly.
parItem.itemID = obj[#"IDI"][#"IDI_ID"];
}
First of all, I'd suggest you to cast JSON data to an NSArray instead of NSMutableArray if you're not going to add or remove new objects to the array.
About "IDI" indices, they are not being parsed as strings like other indices since they're dictionaries. You also should create Parameters object manually instead of casting directly.
An example:
// In Parameters.h
#property (nonatomic, strong) NSString *PAR_VPARAM;
#property (nonatomic, strong) NSDictionary *IDI;
Then after parsing JSON,
for (NSDictionary *obj in resultArray){
Parameters *paritem = [[Parameters alloc] init];
paritem.PAR_VPARAM = [obj valueForKey:#"PAR_VPARAM"];
paritem.IDI = [obj valueForKey:#"IDI"];
int test = (int)[paritem.IDI valueForKey:#"IDI_ID"];
}
This should work well and you can create new properties for other JSON indices.

Get whole object from NSMutableDictionary for current cellForRowAtIndexPath and assign it to a CustomCell

I have the following type of a NSMutableDictionary
(
{
id = 1;
key = value;
key = value;
},
{
id = 2;
key = value;
key = value;
}
)
It contains multiple data of an own Object. Now, in cellForRowAtIndexPath. I created a CustomCell that has a field CustomCell.customObject that should get this object. What I'm trying to do is the following. I want to assign the current entry of the NSMutableDictionary to this field.
Alternatively I could do this (and am doing it right now)
I'm getting the ID like this
NSString *objectId = [[dict valueForKey:#"id"] objectAtIndex:indexPath.row];
And then I'm loading the object from the database. The problem I'm seeing in this, is the doubled request. I mean, I already have the data in my NSMutableDictionary, so why should I request it again?
I don't want to just assign a certain key-value pair, I want to assign the whole current object entry of the NSMutableDictionary. How would I do this?
If the above code (dictionary) is used to show information on tableview there is a mistake in it dictionary should always starts with "Key" not with index. So better make the dictionary to array and then you will have index to get complete information in indexes write this code
NSLog(#"%#",[[newArray objectAtIndex:0]objectForKey:#"id"]);
Hope this will help..

Want to save all the valueForKey in dictionary in either 1 array or dictionary

for (NSDictionary *fbDictionary in self.latestReactionsArray) {
LatestReaction *latestReaction = [[LatestReaction alloc]init];
NSDictionary *subFBDictionary = [fbDictionary objectForKey:#"participant"];
NSString *facebookUserID = [subFBDictionary valueForKey:#"facebook_id"];
NSNumber* reactionIDNum = [fbDictionary valueForKey:#"reaction_id"];
int reactionID = [reactionIDNum intValue];
NSLog(#"what is name%# and %# and %d",facebookUserID, self.latestReactionsArray,reactionID);
}
I want to save all [fbDictionary valueForKey:#"reaction_id"] in an array or dictionary. How do I do this? Thanks.
Try this:
NSArray *reactionIDs = [self.latestReactionsArray valueForKey:#"reaction_id"];
That will give you an array of reaction IDs.
The reflection in Objective C is not powerful enough to get a usable list of properties that you want to map. Instead, you should implement a class method that returns a list of properties you want to map to JSON and use that.
Lastly, a common "Gotcha" is trying to add nil to a dictionary. You'll need to do a conversion from nil to [NSNull null] and back for the conversion to work properly.

iOS sort one array based on order of strings in another array

This is another very specific problem I am trying to solve.
I am pulling a list a twitter user accounts logged into the users settings application. This returns an array with the usernames in the correct order.
I then pass this array to this twitter API:
https://api.twitter.com/1.1/users/lookup.json
The returned array contain all the additional data I need for each user account logged in. The first array contains NSStrings (usernames), the returned array has been parsed to contain dictionaries that have a key and value for the username, name, and profile pic.
Problem now is that the order is completely different than the first array I passed.. This is expected behavior from Twitter, but it needs to be in the exact same order (I will be referencing the original index of the AccountStore which will match the first array, but not the new array of dictionaries).
How can I tell the new array to match the contained dictionaries to be the same order as the first array based on the username key?
I know this sounds confusing, so let me at least post the data to help.
Here is the first array output:
(
kbegeman,
indeedyes,
soiownabusiness,
iphonedev4me
)
Here is what the second array outputs:
(
{
image = "https://si0.twimg.com/profile_images/3518542448/3d2862eee546894a6b0600713a8de862_normal.jpeg";
name = "Kyle Begeman";
"screen_name" = kbegeman;
},
{
image = "https://si0.twimg.com/profile_images/481537542/image_normal.jpg";
name = "Jane Doe";
"screen_name" = iPhoneDev4Me;
},
{
image = "https://twimg0-a.akamaihd.net/profile_images/378800000139973355/787498ff5a80a5f45e234b79005f56b5_normal.jpeg";
name = "John Doe";
"screen_name" = indeedyes;
},
{
image = "https://si0.twimg.com/sticky/default_profile_images/default_profile_5_normal.png";
name = "Brad Pitt";
"screen_name" = soiownabusiness;
}
)
Due to the way Twitter returns the data, it is never the EXACT same order, so I have to check this every time I call these methods.
Any help would be great, would save my night. Thanks in advance!
You want the array of dictionaries be sorted by comparing screen_name value with your first array. Right? Also, the screen name may have different case than your username. Right?
I would use mapping dictionary:
Create dictionary from screen name to user dictionary:
NSArray *screenNames = [arrayOfUserDicts valueForKeyPath:#"screen_name.lowercaseString"];
NSDictionary *userDictsByScreenName = [NSDictionary dictionaryWithObjects:arrayOfUserDicts forKeys:screenNames];
Build final array by finding user dictionary for usernames in your array:
NSMutableArray *sortedUserDicts = [NSMutableArray arrayWithCapacity:arrayOfUsernames.count];
for (NSString *username in arrayOfUsernames) {
NSDictionary *userDict = [userDictsByScreenName objectForKey:username.lowercaseString];
[sortedUserDicts addObject:userDict];
}
First generate a mapping that maps the "screen_name" to the corresponding dictionary
in the second array:
NSDictionary *map = [NSDictionary dictionaryWithObjects:secondArray
forKeys:[secondArray valueForKey:#"screen_name"]];
Then you can create the sorted array with a single loop:
NSMutableArray *sorted = [NSMutableArray array];
for (NSString *name in firstArray) {
[sorted addObject:map[name]];
}
That sort order isn't something that could be easily replicated (i.e. it's not alpha, etc). Instead, you should just use that original NSArray as a guide to match data from the NSDictionary from Twitter. For example:
[twitterDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSInteger index = [yourLocalArray indexOfObject:obj];
if (index != NSNotFound) {
// You have a match, do something.
}
}];
lets name your arrays as firstArray and secondArray.
NSArray *sortedArray = [secondArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [#([firstArray indexOfObject:[obj1 objectForKey:#"name"]]) compare:#([firstArray indexOfObject:[obj2 objectForKey:#"name"]])];
}];

Resources