How to access data "deep" inside a NSDictionary? - objective-c

I am getting a JSON response from a web service as follows into a NSDictionary
NSDictionary *fetchAllCollectionsJSONResponse = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
If I dump the output of the NSDictionary it looks correct like this
2017-10-06 10:11:46.097698+0800 NWMobileTill[396:33294] +[ShopifyWebServices fetchAllCollections]_block_invoke, {
data = {
shop = {
collections = {
edges = (
{
cursor = "eyJsYXN0X2lkIjo0NTI4NTY3MTcsImxhc3RfdmFsdWUiOiI0NTI4NTY3MTcifQ==";
node = {
description = "";
id = "Z2lkOi8vc2hvcGlmeS9Db2xsZWN0aW9uLzQ1Mjg1NjcxNw==";
};
},
{
cursor = "eyJsYXN0X2lkIjo0NTI4NTkwODUsImxhc3RfdmFsdWUiOiI0NTI4NTkwODUifQ==";
node = {
description = "Test Collection 1";
id = "Z2lkOi8vc2hvcGlmeS9Db2xsZWN0aW9uLzQ1Mjg1OTA4NQ==";
};
},
{
cursor = "eyJsYXN0X2lkIjo0NTU0OTMwMDUsImxhc3RfdmFsdWUiOiI0NTU0OTMwMDUifQ==";
node = {
description = Sovrum;
id = "Z2lkOi8vc2hvcGlmeS9Db2xsZWN0aW9uLzQ1NTQ5MzAwNQ==";
};
},
{
cursor = "eyJsYXN0X2lkIjo0NTU0OTMzODksImxhc3RfdmFsdWUiOiI0NTU0OTMzODkifQ==";
node = {
description = Badrum;
id = "Z2lkOi8vc2hvcGlmeS9Db2xsZWN0aW9uLzQ1NTQ5MzM4OQ==";
};
}
);
pageInfo = {
hasNextPage = 0;
};
};
};
};
}
I need to access the "description" attribute deep inside this structure and I cannot figure out how to do it.
I tried the following but it crashes
for (NSDictionary *dictionary in fetchAllCollectionsJSONResponse) {
NSLog(#"jongel %#", [dictionary objectForKey:#"data"]);
}

#Bilal's answer is right. This might be a bit easier to read:
NSArray *edges = fetchAllCollectionsJSONResponse[#"data"][#"shop"][#"collections"][#"edges"];
for (NSDictionary *edge in edges) {
NSString *description = edge[#"node"][#"description"];
NSLog(#"description = %#", description);
}

fetchAllCollectionsJSONResponse is a Dictionary not an Array. Try this.
NSDictionary *fetchAllCollectionsJSONResponse = nil;
NSDictionary *data = fetchAllCollectionsJSONResponse[#"data"];
NSDictionary *shop = fetchAllCollectionsJSONResponse[#"shop"];
NSDictionary *collections = fetchAllCollectionsJSONResponse[#"collections"];
NSArray *edges = fetchAllCollectionsJSONResponse[#"edges"];
// Or a shorter version
// NSArray *edges = fetchAllCollectionsJSONResponse[#"data"][#"shop"][#"collections"][#"edges"];
for (NSDictionary *edge in edges) {
NSString *cursor = edge[#"cursor"];
NSDictionary *node = edge[#"node"];
}

Related

Group same named NSURLComponents queryItems into NSDictionary as array

With no objective-C knowledge I am currently stuck at, what would be a simple task in other languages I know.
For a query string like this:
name1=value1&name2=value2&name1=value3
I need to end up with a NSDictionary in this shape:
#{
#"name1": #{
someField: #[
#"value1",
#"value3",
]
anotherField: #YES,
},
#"name2": #{
someField: #[
#"value2",
]
anotherField: #YES,
}
}
In javascript I could solve this by:
queryItems.reduce((result, item) => {
resultItem = result[item.name] || {
someField: [],
anotherField: true,
}
resultItem.someField.push(item.value)
return {
...result,
[item.name]: resultItem,
}
}, {})
I found this How do I convert url.query to a dictionary in Swift? but I am stuck with Objective-C in this project.
Check the function bellow. I hope I understand what you mean.
NSDictionary* queryItemsToDictionary(NSString* items) {
NSURLComponents* components = [[NSURLComponents alloc] initWithString:[#"?" stringByAppendingString:items]];
NSMutableDictionary* result = [NSMutableDictionary new];
for (NSURLQueryItem* item in components.queryItems) {
NSDictionary* valueForItem = [result objectForKey:item.name];
NSArray* someFieldValues = [valueForItem objectForKey:#"someField"];
if (someFieldValues == nil) {
someFieldValues = #[];
}
[result setObject:#{
#"someField": [someFieldValues arrayByAddingObject:item.value],
#"anotherField": #YES
} forKey:item.name];
}
return result;
}
This is how you can try it:
NSDictionary* dictionary = queryItemsToDictionary(#"name1=value1&name2=value2&name1=value3");
NSLog(#"%#", dictionary);

how to parse this JSON in OBJ c

I receive this JSON string from a web process
{
"result":"ok",
"description":"",
"err_data":"",
"data":[
{
"id":"14D19A9B-3D65-4FE2-9ACE-4C2D708DAAD8"
},
{
"id":"8BFD10B8-F5FD-4CEE-A307-FE4382A0A7FD"
}
]
}
and when I use the following to get the data:
NSError *jsonError = nil;
NSData *objectData = [ret dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json= [NSJSONSerialization JSONObjectWithData: objectData options:kNilOptions error: &jsonError];
NSLog(#"data: %#",[json objectForKey:#"data"]);
it gets logged as:
(
{
id = "14D19A9B-3D65-4FE2-9ACE-4C2D708DAAD8";
},
{
id = "8BFD10B8-F5FD-4CEE-A307-FE4382A0A7FD";
}
)
How can I parse the data as an NSDictionary with value and keys?
The web returns an object that has a property which is an array of objects, so...
NSDictionary *json= // your code
NSArray *array = json[#"data"];
for (NSDictionary *element in array) {
NSLog(#"%#", element);
// or, digging a little deeper
NSString *idString = element[#"id"];
NSLog(#"id=%#", idString);
}

Parse a nested Json to NSDictionary in iOS

I Have a nested Json :
[
{
"result":"1",
"roleId":4
},
{
"projectInfo":[
{
"result":true
},
{
"Project":[
{
"ProjectId":5378,
"ProjectName":"ASAG",
"CountryId":146,
"ProjectGroupId":743,
"Description":"Axel Spinger AG"
},
{
"ProjectId":5402,
"ProjectName":"BIZ",
"CountryId":146,
"ProjectGroupId":759,
"Description":"Bizerba Win 7 BAU"
},
{
"ProjectId":5404,
"ProjectName":"BOM",
"CountryId":146,
"ProjectGroupId":743,
"Description":"Bombardier Transportation ThinApp Migration"
},
{
"ProjectId":5394,
"ProjectName":"REDBULL",
"CountryId":149,
"ProjectGroupId":762,
"Description":"Red Bull Mac Packaging"
},
{
"ProjectId":5397,
"ProjectName":"VHV",
"CountryId":146,
"ProjectGroupId":743,
"Description":"VHV Win7 Migration"
}
]
}
]
}
]
What I need is to separate it into small pieces to get value of some specific key like this answer: How to parse JSON into Objective C - SBJSON
My code is :
SBJsonParser* jParser = [[SBJsonParser alloc] init];
NSDictionary* root = [jParser objectWithString:string];
NSDictionary* projectInfo = [root objectForKey:#"projectInfo"];
NSArray* projectList = [projectInfo objectForKey:#"Project"];
for (NSDictionary* project in projectList)
{
NSString *content = [project objectForKey:#"ProjectId"];
NSLog(#"%#", content);
}
But I got the error when trying to get projectInfo from root node. Is there anything wrong with my code ? Please provide me an example to split up my JSON. Any help would be great.
You JSON contains like nested array. Just spit each content into a dictionary to get the result.
Working Code:
SBJsonParser* jParser = [[SBJsonParser alloc] init];
NSArray* root = [jParser objectWithString:string];
NSDictionary* projectDictionary = [root objectAtIndex:1];
NSArray* projectInfo = [projectDictionary objectForKey:#"projectInfo"];
NSDictionary* projectData = [projectInfo objectAtIndex:1];
NSDictionary *projectList = [projectData objectForKey:#"Project"];
NSLog(#"\n\n Result = %#",projectList
);
for (NSDictionary* project in projectList)
{
NSString *content = [project objectForKey:#"ProjectId"];
NSLog(#"\n Project Id =%#", content);
}
According to your JSON structure, your top level structure is an array, not a dictionary.
Try this:
SBJsonParser* jParser = [[SBJsonParser alloc] init];
NSArray* root = [jParser objectWithString:string];
NSDictionary* projectDictionary = [root objectAtIndex:1];
NSArray* projectInfo = [projectDictionary objectForKey:#"projectInfo"];

I pass a NSDictionary, but the function get nil

This is weird. I have a NSDictionary. I pass it to a method. The NSDictionary is filled, but the reciever get nil. What could be?
[self.manager POST:url parameters:params success:^(NSURLSessionDataTask *task, NSDictionary *responseObject)
{
NSString *code = responseObject[kCODE];
if ([code isEqualToString:rAPI_SUCCESS]) {
fulfiller([[ResponseDataModel alloc] initWithDictionary:responseObject]);
I put a breakpoint in the fullfiler line, then this is the value:
Printing description of responseObject:
{
code = "API_SUCCESS";
data = {
cliente = {
celular = ******;
email = "test#****.com";
nombre = test;
"user_token" = ACDF*****4;
"ver_celular" = 1;
};
};
message = "The operation was successful";
success = 1;
}
Now in the receiver:
- (id)initWithDictionary:(NSDictionary *)dictionary {
if (!nsDictionaryClass) nsDictionaryClass = [NSDictionary class];
Printing description of dictionary:
(NSDictionary *) dictionary = <variable not available>
(Self is a valid reference)
This is with Xcode Version 5.1.1 (5B1008) in debug mode.

JSON data messed up in AFNetworking POST request

I am sending a request with AFNetworking for Objective-C. When I NSLog the parameters this is the object I am sending:
games = (
{
id = 50;
p = 8;
ts = 0;
tt = ();
tw = 0;
ys = 35150;
yt = {
156424496 = "37.416669";
156609008 = "56.661210";
....
252846816 = "7.075133";
252856944 = "61.329850";
};
yw = 0;
}, ...
This is what the server receives.
games = (
{id = 50;},
{p = 8;},
{ts = 0;},
{tw = 0;},
{ys = 35150;},
{
yt = {156424496 = "37.416669";};
},
{
yt = {156609008 = "56.661210";};
},
...
{
yt = {252846816 = "7.075133";};
},
{
yt = {252856944 = "61.329850";};
},
{yw = 0;},
...
It is as if it is taking each property of my object and creating a new object with it. The worse part is that it's taking the multiple objects that are in the array and putting all properties of all objects and turning them into separate object on the same depth of the array.
Here is the code I am using to send this off:
NSArray *games = [ResourceManager getAllGames];
NSMutableArray *gamesArray = [[NSMutableArray alloc] initWithCapacity:[games count]];
for(Game *g in games)
{
[gamesArray addObject:[g toDictionary]];
}
User *user = [ResourceManager getUser];
NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:gamesArray, #"games", user.id, #"user_id", nil];
NSLog(#"PARAMS: %#", params); <- this is the first block of code above
[self postPath:API_SYNC_GAMES_URL parameters:params success:^(AFHTTPRequestOperation *operation, id JSON)
{
}
I have not been able to figure out why this would be happening, and I am all out of guesses. If someone could point me in the right direction it would be very appreciated.
UPDATE
If I post a single object rather than an array of the objects it arrives at the server successfully.
I was able to solve this issue by using an NSDictionary instead of an array. Each object I have has a unique key so I used that key for the NSDictionary like so:
NSMutableDictionary *gamesArray = [[NSMutableDictionary alloc]
initWithCapacity:[games count]];
for(Game *g in games)
{
[gamesArray setObject:[g toDictionary]
forKey:[NSString stringWithFormat:#"%#", g.id]];
}
That seems to have solved the issue.
Take a look at my answer here:
How can I POST an NSArray of NSDictionaries inside an NSDictionary without problems?
It solves all your problems.