How to handle JSON exception objective c - objective-c

Before I make url, which I will use to fetch json, user has to input some data first.
If the input data is wrong, the JSON will not be fetched properly.
But I cannot figure out how to handle that exception of calling JSON with wrong url.
this is my code:
NSError *error;
NSMutableDictionary* json = [NSJSONSerialization
JSONObjectWithData:url
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
if (error){
NSLog(#"%#",[error localizedDescription]);
}
else{
#try {
if (json){
[Constants shared].salt = json[#"salt"];
The last line of code is where the exception occurs, since the user had put the wrong input.
SO obviously, there wont be a proper json response fetchet, and there will be no "salt" object.
Error I get is:
-[__NSArrayM objectForKeyedSubscript:]: unrecognized selector sent to instance 0x146aa310
I tried putting json fetching in #try #catch, but it didn't work out.
Any suggestions ?
EDIT:
this is the json responce I get, when the user types in the right code:
{
user_id: "22066",
salt: "ce8c0f9e3e1add06bebc1acded7b692b68efddb87bfdc5bb1fb516f6a3e24425"
}
This is what i get, when the code is invalid:
[ ] (empty array)

The problem isn't that the dictionary lacks an object for the key #"salt", it's that json isn't a dictionary in the first place. Take a close look at the error message and you'll see that it's an array. The problem isn't the key, but the fact that arrays don't respond to -objectForKeyedSubscript:.
Accordingly, when you get an object back from -JSONObjectWithData:..., check that it's not nil and that it is in fact a dictionary before you try to access its contents. You can check it like this:
if ([json isKindOfClass:[NSDictionary class]]) {
// put the code that accesses `json` here
}
That condition will be false if json is nil or something other than a dictionary. You could add an else clause to take any necessary steps to recover if you're relying on getting the data.

Related

Getting "unrecognized selector sent to instance" in code for ios8

This code work in ios7, but I am now getting the error :
-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance
.m file
//get the JSON response
NSDictionary *jsonData = [NSJSONSerialization
JSONObjectWithData:urlData
options:NSJSONReadingMutableContainers
error:&error];
//Parses the "success" value
success = [jsonData[#"success"] integerValue];
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSArray *profileJSON=jsonData[#"myProfile"];
for (NSDictionary* dict in profileJSON)
{
NSLog(#"First_Name: %#", dict [#"first_name"]);
...
The error is happening on the NSLog statement and from a little research it is complaining about the dict[#"first_name"]);
login.py
....
#Query for user
db_cursor = db.cursor(MySQLdb.cursors.DictCursor)
db_query = """SELECT users.email, users.first_name, users.profile_pic_path, \
FROM users,data WHERE users.email='%s' \
AND users.user_id=data.user_id""" % user_email
db_cursor.execute(db_query)
#If there is one record containing the username check password
if(db_cursor.rowcount == 1):
user_profile = db_cursor.fetchone()
...
json_obj= {'success': 1, 'myProfile': user_profile,}
...
JSON Output:
{'myProfile': {'first_name': 'Matt', 'email': 'matt#email.com', 'profile_pic_path': 'default'}, 'success': 1}
All this code was working, I have not changed anything.
Any help will be greatly appreciated!!!!
dict is not a dictionary. It is a string. Print it and you'll know which string it is.
More likely than not, your JSON is not what you think it is. In particular, the myProfile value is a string instead of a dictionary.
What happens if fetchone() returns None; do you end up with a string in your JSON?
Changed in the .m
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSArray *profileJSON=jsonData[#"myProfile"];
for (NSDictionary* dict in profileJSON)
{
...
to
//Was it successful?
if(success){
//successful, save the profile gathered into global gMyProfile
NSDictionary* dict=jsonData[#"myProfile"];
//no more for loop
...
The python JSON module returns a single dictionary instead of an array of a single dictionary when there is one element. If there are multiple it returns an array of dictionaries.
Still don't know why this didn't give me trouble in ios7 but did in ios8.

Parse JSON String and array with NSJSONSerialization issue?

This is the code i have so far
// Parse data using NSJSONSerialization
NSError *error = nil;
NSArray *JsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error: &error];
if(!JsonArray)
{
NSLog(#"Error Parsing Data: %#", error);
}
else
{
for(NSDictionary *event in JsonArray)
{
if([[event description] isEqualToString:#"error"])
{
// Get error number? I am confused by this part
NSLog(#"Element: %#", [event objectForKey:#"error"]);
}
else
{
NSLog(#"Element: %#", [event description]);
}
}
}
this is the JSON Data that parses correctly:
[{data string}, {data strings}]
This only gives me the string "error" and not the int as well:
{"error":0}
I am echoing this data from a PHP script if that helps any. Am i just doing it wrong, or did i miss something?
Your problem is that when you receive an error, you get back an NSDictionary and not an NSArray. This should work:
if ([jsonObject isKindOfClass:[NSArray class]]) {
// no error: enumerate objects as you described above
} else if ([jsonObject isKindOfClass:[NSDictionary class]]) {
// error: obtain error code
NSNumber *errCode = jsonObject[#"error"];
} else {
// something bad's happening
}
Stylistic pieces of advice:
Don't call your object JsonArray, since it's not always an array. Call it jsonObject.
Don't start variable names with capital letters.
Would be great if you had posted the complete JSON document that you are trying to parse, because without that, there is absolutely no chance to figure out whether your code is anywhere near correct. The example [{data string}, {data strings}] that you gave is most definitely not a correct JSON document, so trying to parse it will return nil. {"error":0} is a dictionary with a single key "error" and a value 0. Having dictionaries with a single key is let's say unusual.
A JSON document contains either an array or object (using JSON terms) which will be turned either into an NSArray* or an NSDictionary*. You should know whether you expect an array or dictionary. If you expect an NSArray, check that [jsonObject isKindOfClass:[NSArray class]]. If you expect an NSDictionary, check that [jsonObject isKindOfClass:[NSDictionary class]]. If you don't do that then the wrong JSON document will either crash your app or produce total nonsense.
If you have an array then you will usually iterate through the elements of the array and handle each one in turn. If you have a dictionary you will usually look up keys that you know how to handle. What you are doing, iterating through an array of dictionaries, and checking for a dictionary with a key of "error", that's a very strange design of your JSON document.
And lookup what the "description" method does. "description" is what NSLog calls to find out what to print when it is asked to print an object. For an NSDictionary with a single key "error" and a value 0, it would return something like "error:0" which is of course not the same as "error".
NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"jsonDic: %#", [jsonDic objectForKey:#"string"]);

ERROR happened while deserializing the JSON data

-(void) conn:(NSString *)method{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block NSDictionary *resultBlock = nil;
dispatch_sync(concurrentQueue, ^{
/* Download the json here */
//Create webservice address
NSString *webService = [_baseURL stringByAppendingString:_webService];
//NSLog(#"%#", webService);
//Create error object
NSError *downloadError = nil;
//Create the request
NSMutableURLRequest *req = [self initRequest:webService method:method];
if(req != nil){
//Request the json data from the server
NSData *jsonData = [NSURLConnection
sendSynchronousRequest:req
returningResponse:nil
error:&downloadError];
if(downloadError!=nil){
NSLog(#"DOWNLOAD ERROR %#", downloadError);
}
NSError *error = nil;
id jsonObject = nil;
if(jsonData !=nil){
/* Now try to deserialize the JSON object into a dictionary */
jsonObject = [NSJSONSerialization
JSONObjectWithData:jsonData
options:kNilOptions
error: &error];
}
//Handel the deserialized object data
if (jsonObject != nil && error == nil){
NSLog(#"Successfully deserialized...");
if ([jsonObject isKindOfClass:[NSDictionary class]]){
resultBlock = (NSDictionary *)jsonObject;
//NSLog(#"Deserialized JSON Dictionary = %#", resultBlock);
}
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
NSLog(#"Deserialized JSON Array = %#", deserializedArray);
} else {
/* Some other object was returned. We don't know how to deal
with this situation, as the deserializer returns only dictionaries
or arrays */
}
}
else if (error != nil){
NSLog(#"An error happened while deserializing the JSON data. %#", error);
}else{
NSLog(#"No data could get downloaded from the URL.");
//[self conn:method];
}
}
});
dispatch_sync(dispatch_get_main_queue(), ^{
/* Check if the resultBlock is not nil*/
if(resultBlock != nil){
/*Set the value of result. This will notify the observer*/
[self setResult:resultBlock];
}
});
});
}
Why do I get the following error?
An error happened while deserializing the JSON data. Error
Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be
completed. (Cocoa error 3840.)" (JSON text did not start with array or
object and option to allow fragments not set.) UserInfo=0x20839f80
{NSDebugDescription=JSON text did not start with array or object and
option to allow fragments not set.}
When I change it to
/* Now try to deserialize the JSON object into a dictionary */
jsonObject = [NSJSONSerialization
JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error: &error];
}
I get the following error:
An error happened while deserializing the JSON data. Error
Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be
completed. (Cocoa error 3840.)" (Invalid value around character 0.)
UserInfo=0x20888760 {NSDebugDescription=Invalid value around character
0.}
I changed my connection from LTE to wifi and now I get
504 error and NSLog(#"No data could get downloaded from the URL.");
You should fix these issues in your code first:
Properly check for errors in methods which provide a pointer to a reference to an NSError object as the last parameter, e.g.: - (BOOL) doSomething:(NSError**)error, or -(NSData*) doSomething:(NSError**)error
In order test for an error correctly, you have to check the return value of the method only. Those methods indicate an error condition with a "special return value". For example, they return NO or nil - as always specified in the documentation. Only after the method indicated an error, the provided error parameter contains a meaningful value - that is, it points to an NSError object created by the method. Note that this parameter may also become none NULL when the method succeeded, in which case that has no "meaning".
Web services usually can provide several formats of the requested resource. If you don't specify which format you want the server to encode the resource, you get a default format - which is not necessarily JSON.
In order to be explicit about the desired format of the resource, set a corresponding "Accept" header. For example, if you wish the format in JSON you would set a header: "Accept: application/json" in your request.
Web services may have reasons not to respond with the resource you requested. In order to be sure you got the response that you requested, you need to check the response for status code and MIME type in order to ensure you actually received a JSON response.
It seems, you are a bit uncertain about how to use dispatch functions to your advantage. If you use the synchronous convenient method sendSynchronousRequest:... You certainly need to wrap it in only one dispatch_async function. If you then want to set the result on the main thread, you certainly want to use dispatch_async, not dispatch_sync.
However, it would be an improvement if you would use sendAsynchronousRequest:... instead. And only if you would use NSURLConnection in asynchronous mode and implement the NSURLConnection delegate methods - which I strongly recommend - it would actually become great ;)
So, I think, once you fixed your code, you may be able to answer the original question yourself, or get better error responses from the server, or the error magically disappeared ;)

Cocoa Touch JSON Handling

I've been looking for a while now and I can't seem to find a solution.
I am trying to format a JSON object that is being held in an NSData *receivedData.
The format of the JSON is:
[
{
"name":"Stephen",
"nickname":"Bob"
},
{
"name":"Rob",
"nickname":"Mike"
},
{
"name":"Arya",
"nickname":"Jane"
}
]
Normally I would use "NSJSONSerialization JSONObjectWithData:" of the NSDictionary. Then I would normally take the root of the JSON (in this case it would be something like "People":) and create the array from that root object. However as you can see this response is simply an array without a root object. I'm not sure how to handle this. The end goal is to have an array of Person objects, populated with the data in the JSON.
Edit: I would also like to add that I want to keep it native without third party libraries.
OK for anyone reading this. I just figured it out. Instead of formatting the initial NSData into a dictionary, you put that straight into an array. Then create a dictionary for each object in the array. Like so:
NSArray *response = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSDictionary* json = [responseArray objectAtIndex:0];
NSLog (#"%#",[json objectForKey:#"nickname"]);

Parsing JSON data to an array

I get the following error whenI launch my app
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '- [COViewController fetchAppNetData]: unrecognized selector
sent to instance 0x716d200'
Basically I am unable to find out how to parse the JSON data to my array. The structure of my JSON is as follows
{
"meta": {},
"data": []
}
I know that meta is a dictionary and data is an array. But when I try to use the following piece of code I get the above error
- (void)fetchAppNetData:(NSData *)responseData
{
//parse JSON data
NSError *error;
NSDictionary* appNet_json = [NSJSONSerialization
JSONObjectWithData:responseData options:kNilOptions error:&error];
NSArray* appNetTimeline = [[appNet_json objectForKey:#"meta"]
objectForKey:#"data"];
NSLog(#"AppNet Timeline : %#",appNetTimeline);
}
How do I make sure that I can identify the structure of JSON properly next time, so that I can avoid this sort of issue? I am extremely sorry to come up with such kind of doubts
The error has nothing to do with the content of the method -fetchAppNetData:. That method is not even getting called.
The error is saying that you tried to invoke a method of that name on an object that doesn't respond to it. You've sent that message to an instance of class COViewController, but that's evidently not the class that implemented the method you posted.