I am receiving a JSON object like this:
{"data":null,
"error":1,
"error_code":"InvalidSID",
"sid":"",
"num_rows_total":0,
"last_insert_id":0,
"error_info":"Comment...",
"error_data":[]}
and JSONKit using this code:
NSString *responseString = [request responseString];
NSDictionary *requestDictionary = [responseString objectFromJSONString];
if([[requestDictionary objectForKey:#"error"] intValue]) {
if([#"InvalidSID" isEqualToString:[requestDictionary objectForKey:#"error_code"]]) {
[self.navigationController popViewControllerAnimated:YES];
}
}
produces such output:
{
data = "<null>";
error = 1;
"error_code" = InvalidSID;
"error_data" = ();
"error_info" = "Comment...";
"last_insert_id" = 0;
"num_rows_total" = 0;
sid = "";
}
The problem is, that this if statement is never called because of missing quotation marks around InvalidSID. Is there any known problem with JSONKit that makes those quotation marks disappear?
You are confusing the "description" output from NSDictionary with the value of a key. You also could have saved yourself a lot of time (that is the time you posted this to the time you get some response) by using some simple detective work.
I assume that what you call "output" above is the result of
NSLog(#"%#", requestDictionary);
So after that line try this:
// Just to be complete
id ee = [requestDictionary objectForKey:#"error"];
NSLog(#"error=%# intValueOfError=%d classOfErrorCode=%#",
ee, [ee intValue], NSStringFromClass([ee class]) );
// Where I suspect you may discover something
id ec = [requestDictionary objectForKey:#"error_code"];
NSLog(#"errorCode=%# classOfErrorCode=%#",
ec, NSStringFromClass([ec class]) );
We do that since something is obviously wrong here, we want to find out more about the objects we have in hand. I am going to guess if you do the above you will discover something you did not expect.
Related
I have an NSDictionary, named "thisList", and I need to get the value of its key "list_collection".
Xcode indicates that the value is a "NSSingleEntryDictionary".
The value itself contains an array with yet another dictionary.
Please take a look at the screenshot:
Now, no matter what I try (objectforKey/valueforKey) or whatever type of object I initialize (NSArray/NsMutableArray/NSDictionary/NSMutableDictionary) I end up with a nil value.
Apparently, I miss some essential knowledge on how to handle this.
My question: how should I initialize an object with the value of the key "list_collection".
Here is a (partial) dump of the json:
Printing description of thisList:
{
archived = 0;
"chapter_part" = "";
"chapter_title" = "";
comment = "";
"cover_id" = "<null>";
"created_at" = "2017-01-06T12:59:04.000+01:00";
"date_created" = "06 January 2017";
deleted = 0;
id = 141384502;
isMyList = 1;
keywords = (
);
"list_collection" = {
lists = (
{
"speech_locale" = EN;
subject = engels;
words = (
{
word = attitude;
},
The to me most logical approach would be:
NSDictionary * myDic = [thisList objectForKey:#"list_collection"];
Note: I didn't explicitly initialize 'myDic' here.
To put things in context, here is my code:
NSString * hlists = [json objectForKey:#"lists"];
NSData* data = [hlists dataUsingEncoding:NSUTF8StringEncoding];
NSArray *wrtsLists = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParsingError];
Lists = [[NSMutableArray alloc]init];
for (NSDictionary *thisList in wrtsLists){
WordList* theList = [[WordList alloc]init];
theList.title = [thisList valueForKey:#"title"];
[Lists addObject:theList];
NSDictionary *myDic = thisList[#"list_collection"];
>>>>this is where I put a breakpoint. myDic is nil here
}
Thanks for your insights.
You can simply get "list_collection" array from "thisList" using by this code
NSDictionary *myDic = thisList[#"list_collection"];
In the end, I figured out, that it was an Xcode problem.
The Debug area just didn't correctly display the values of my objects.
I restarted Xcode, and things started to work as expected.
I lost several hours of my life on this. But I learned a lot, thanks to your good advises.
Try this hope it helps You
NSDictionary *myDic = [thelist valueForKey:"list_collection"];
I know there's a lot of questions like this around, but I think my situation's a tad different.
int i = 0;
while (_data[#"VerticalState%i", i] != nil) {
// do things
i++;
}
For example, one 'level' that has 3 VerticalState properties will be implemented as such: VerticalState0, VerticalState1, VerticalState2.
I want to read in those values using that while loop condition above, and it should stop when i = 3. How can I make the idea of that code above work (with some other configuration obviously). FYI, _data is an NSDictionary* instance variable, already loaded with the plist information.
You appear to want to create a dictionary key from a string format. You need to use NSString stringWithFormat:.
while (_data[[NSString stringWithFormat:#"VerticalState%i", i]] != nil) {
Though it would be better to write the loop like this:
int i = 0;
while (1) {
NSString *key = [NSString stringWithFormat:#"VerticalState%i", i];
id value = _dict[key];
if (value) {
// do things
i++;
} else {
break;
}
}
I fetch values from dictionary and need to display in UITableView, but everything works fine.
On some spot it stops running and shows thread
-[__NSCFString objectAtIndex:]: unrecognized selector sent to instance 0xbfa7670
The code below, which I used to fetch value..
[NSString stringWithFormat:#"%#",[[pageCat1 valueForKeyPath:#"img3"] objectAtIndex:indexPath.row]]
My values are fetched properly in dictionary but lags to display it?
pageCat (
{
img3 = "http://xxx.in/images/page_cat_img/75x75/4.jpg";
name = "PVC Flexible Wires";
page = (
{
id = {
text = 1;
};
img4 = "http://xxxx.in/images/page_img/75x75/1.jpg";
name = "SINGLE CORE FLEXIBLE WIRES ABOVE 6 SQMM";
},
{
id = {
text = 72;
};
img4 = "http://xxx.in/images/page_img/75x75/72.jpg";
name = "SINGLE CORE FLEXIBLE WIRES BELOW 6 SQMM";
}
);
},
{
img3 = "http://xxx.in/images/page_cat_img/75x75/3.jpg";
name = "Bare Copper Wires";
page = {
id = {
text = 29;
};
img4 = "http://xxx.in/images/page_img/75x75/29.jpg";
name = "Tinned Copper Fuse Wires";
};
},
{
img3 = "http://xxx.in/images/page_cat_img/75x75/48.jpg";
name = "Properties of Wire";
page = {
id = {
text = 85;
};
img4 = "http://xxx.in/images/page_img/75x75/85.jpg";
name = "Wires - Normal, HR - PVC, FR, FRLS & Zero Halogen";
};
}
)
Actually look at the log value, it has array and set of values.. i can't find whether it is in what form..
Can anyone help me to find the solution??
Thanks,
Yazh
it looks like [pageCat1 valueForKeyPath:#"img3"] returns a NSString and not a NSArray like you expect
make sure that it returns a NSArray before applying objectAtIndex:
it seems that pageCat1 is a NSArray so you need to write something like:
NSString *path = pageCat1[0][#"img3"];
...
As the error already tells, [pageCat1 valueForKeyPath:#"img3"] returns a NSString and you are calling objectAtIndex: on it which is not recognized for this class. Obviously, pageCat1 differs from what you expected.
Try NSLog(#"%#", pageCat1); to see what it really looks like.
// Edit
pageCat1 (as seen in your update) is an NSArray that contains items of type NSDictionary. What you really want to do is NSString *imgURL = [[pageCat1 objectAtIndex:indexPath.row] objectForKey:#"img3"];
Explanation:
1. [pageCat1 objectAtIndex:indexPath.row] returns a NSDictionary
2. [__dictionary__ objectForKey:#"img3"] returns the NSString containing your image URL
Actually I used XML data, for that i used third party to parse data. Its all of third party which parsed alternate data as array and other as non-array. Finally I check the array with
isKindOfClass
and convert it into array. Therefore my problem in app solved. :-)
Thanks to all who help me..
Please try this one:
//Assuming json is your main dictionary
NSDictionary *pageCat = [json objectForKey:#"pageCat"];
NSMutableArray *array = [[pageCat valueForKey:#"img3"]mutableCopy];
NSLog(#"Value=%#", [array objectAtIndex:indexPath.row]);
I make a request to the Instapaper API, and it's supposed to return JSON. It returns something close to JSON, but not completely, like follows:
2013-05-30 19:54:20.155 --[53078:c07] (
{
type = meta;
},
{
"subscription_is_active" = 1;
type = user;
"user_id" = --;
username = "--#gmail.com";
},
{
"bookmark_id" = 387838931;
description = "";
hash = YHwQuwhW;
"private_source" = "";
progress = 0;
"progress_timestamp" = 0;
starred = 0;
time = 1369954406;
title = "Adobe Finally Releases Kuler Color-Picking App for iPhone - Mac Rumors";
type = bookmark;
url = "http://www.macrumors.com/2013/05/30/adobe-finally-releases-kuler-color-picking-app-for-iphone/";
},
How do I then process this? Can I take it and turn it into an NSDictionary even though it doesn't seem to be valid JSON?
From Instapaper API Docs:
Instapaper strings are always encoded in UTF-8, and Instapaper expects all input to be in UTF-8.
Unless otherwise noted, output from every method is an array. The output array is returned as JSON by default.
You can specify a jsonp parameter with a callback function name, e.g. jsonp=myCallback, to use JSONP and wrap the output in a call to the specified function.
So there is no way you will get not valid JSON!
Try following code:
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL urlWithString:#"http://your-instapeper-API-link"] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id serializationJSON = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
And then you can log what is wrong or if result is what you expect:
NSLog(#"class of JSON input: %# \n and possible error: %#",[serializationJSON class],error);
Of course you should expect Array and no error.
EDIT ... based on coment code:
Based on docs you should get Array or Dictionary. Please add this core instead your line #23 (numer from here):
if([JSON isKindOfClass:[NSDictionary class]]) {
NSDictionary *jsonDictionary = JSON;
NSLog(#"%#",[jsonDictionary allKeys]);
} else {
NSLog(#"JSON object class: %#",[JSON class]);
}
and please show us output.
One more thing:
You get array from request. Great! This is a valid JSON. So you need to debug it. As i said it's a shame is not a unlimited acccess public API, so i can look into it. But now you have to debug your result. I see in your code that you are trying to access bookmarks. So i look into Bookmarks section in docs and this is some kind of list (NSArray). So if you don't know what result you want. You should print them into log (or set a breakpoint). Replace code from my earlier update with this simple log:
NSDictionary *resultDictionary;
if([JSON isKindOfClass:[NSArray class]]) {
NSArray *jsonArray = JSON;
NSLog(#"so json is an array with %i objects",[jsonArray count]);
for(id objectInsideArr in jsonArray) {
NSLog(#"object in array [class]: %# [value]: %#",[objectInsideArr class],objectInsideArr); //if here you find NSDictionary maybe is this dictionary you are looking for. I'm not sure what it is.
if([objectInsideArr isKindOfClass:[NSDictionary class]]) {
resultDictionary = [[NSDictionary alloc] initWithDictionary:objectInsideArr];
}
}
}
If it were me I would write a custom formatter to get it into JSON format and then use NSJSONSerialization once I know it is valid. What you posted is so far from valid there is no way it would work. I'm surprised they are returning it in that format, do they provide some kind of library for consuming their services?
If you want something even simpler, I can give you my CGIJSONObject library that will handle JSON using reflection - you just need to mirror the keys in APIs with your classes andit is good to go.
I'm trying to get the nearby places using the foursquare api.
Here's the json data that is returned from
NSDictionary *results = [jsonString JSONValue];
NSLog(#"%#", results);
(
{
code = 200;
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
errorType = deprecated;
},
{
groups = (
{
items = (
{
categories = (
{
icon = "https://foursquare.com/img/categories/parks_outdoors/default.png";
id = 4bf58dd8d48988d163941735;
name = Park;
parents = (
"Great Outdoors"
);
pluralName = Parks;
primary = 1;
shortName = Park;
}
);
Then I try to get the list of the groups in an array with
NSArray *groups = [ (NSDictionary *)results objectForKey:#"groups"];
This returns the following error
2011-11-05 11:42:12.907 XperienzApp[1972:207] No of results returned: 0 Results : (null)
2011-11-05 11:42:13.225 XperienzApp[1972:207] -JSONValue failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=3 \"Unrecognised leading character\" UserInfo=0x5849cd0 {NSLocalizedDescription=Unrecognised leading character}"
)
2011-11-05 11:42:13.225 XperienzApp[1972:207] No of results returned: 0 Results : (null)
How should I parse this?
Edit:
I tried the suggested technique, this gives me an array
id groups = [[(NSDictionary *)results objectForKey:#"response"] objectForKey:#"groups"];
if ([results count] > 1){
NSLog(#"groups class %#\ngroups %# %d", groups, [groups class], [groups count]);
The log output is of the form:
{
categories = (
{
icon = "https://foursquare.com/img/categories/nightlife/danceparty.png";
id = 4bf58dd8d48988d11f941735;
name = Nightclub;
parents = (
"Nightlife Spots"
);
pluralName = Nightclubs;
primary = 1;
shortName = Nightclub;
}
);
contact = {
};
hereNow = {
count = 0;
};
id = 4eb33ba561af0dda8f673c1b;
location = {
address = "144 Willow St 4R";
city = Brooklyn;
crossStreet = Pierrepont;
distance = 462;
lat = "40.696864";
lng = "-73.996409";
postalCode = 11201;
state = NY;
};
name = "Entertainment 720, Ltd.";
stats = {
checkinsCount = 3;
tipCount = 0;
usersCount = 1;
};
verified = 0;
}
);
name = Nearby;
type = nearby;
}
)
groups __NSArrayM 1
This is again not json and is hard to parse, how do I get the output in json.
I'm the iPhone lead at foursquare. I'll try to take a stab at what's going on here.
First of all, I highly recommend you use JSONKit for your parser. It's lightweight and insanely fast: https://github.com/johnezang/JSONKit
It appears that you are parsing the JSON properly and getting the dictionary properly. Then you are logging the parsed object, not the original JSON. The output you are seeing is how Objective-C chooses to serialize the parsed dictionary to text. It is definitely not JSON. Using JSONKit, you could send the JSONString selector to your parsed result and convert it back to JSON and log that.
If you could provide some details on the problem you are trying to solve, I might be able to help you out more. And as Maudicus said, please pay attention to the error you are getting back. You don't want your app to break when we make the change to the API.
If the output below NSLog(#"%#", results); is your log statement. It appears your results variable is an array of dictionary objects.
Try to log the class of results to verify that NSLog(#"%#", [results class]);
If it is an array your groups object is the second object.
if ([results count] > 1)
id groups = [results objectAtIndex:1];
NSLog(#"groups class %#\ngroups %#", [groups class], groups);
Keep doing this until you understand the format of your data
Also the line
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
should be cause for concern. Check the documentation on foursquare for the current way of getting groups.