Here is what I want to parse.
{
"Words": {
"subjugate": "To conquer. ",
"contemplate": "To consider thoughtfully. ",
"comprise": "To consist of. ",
"pollute": "To contaminate. "
}
}
Here is a very stripped and over-simplified way to handle getting response data back from a server in JSON and serializing the JSON to an NSDictionary:
// this is just for example purposes, in this example the code is already running on a background thread so sending it synhcronously is OK, and I've already created the request object
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// if we don't have response data
if (!responseData) {
// handle that we got no response from the server
}
if (error) {
// handle the request error
}
// serialize the JSON result into a dictionary
NSError *serializationError = nil;
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 &serializationError];
if (serializationError) {
// handle the error turning the data into dictionary
}
NSDictionary *wordsDictionary = resultDictionary[#"words"];
NSString *exampleValue = wordsDictionary[#"subjugate"]; // will be "To conquer." if everything goes to plan
You can parse as bellow
NSData *data = [#"{\"Words\":{\"subjugate\":\"To conquer.\",\"contemplate\":\"To consider thoughtfully.\",\"comprise\":\"To consist of.\",\"pollute\":\"To contaminate.\"}}" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if(error)
{
NSLog(#"Error : %#", error);
}
else
{
NSLog(#"%#", json);
}
Related
How to check if a NSString is a valid json string in iOS? Did oc have the api to check a nesting is a valid json string ?
you can use NSJSONSerialization to convert NSString to Dictionary. If invalid json string format function will return error
NSError *error = nil;
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error) {
// handle error here
}
Check to NSString class is valid..
NSError *err;
id objJson = [NSJSONSerialization JSONObjectWithData:[yourstring dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&err];
if ([objJson isKindOfClass:[NSString class]]) {
// valid string
} else {
// Not valid string
}
I have since changed my implementation to not do this anymore, but I would be interested in knowing if the following could lead to issues - take for example a process that has multiple steps, each involving passing a reference to an NSError object. If you were to reuse this error object each step along the way, would that reference be negatively effected in some way, perhaps leading to some sort of memory management/dealloc crash?
Example (most of the in-between code has been omitted)
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
if (!data) {
return error;
}
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!responseData) {
return error;
}
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (!resultDictionary) {
return error;
}
Even though the error is never "used" twice, meaning the error will be nil (it seems) the next time its reference is passed to another method, could the reference be effected in some way at any of the steps along the way?
Original code prior to editing in response to jlehr's comments:
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
if (error) {
return;
}
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error) {
return;
}
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
return;
}
EDIT: To anyone coming to this at a later date, the information jlehr is referring to can be found here:
When dealing with errors passed by reference, it’s important to test
the return value of the method to see whether an error occurred, as
shown above. Don’t just test to see whether the error pointer was set
to point to an error.
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html
According to Apple's documentation, you should never check an NSError object returned by reference. Instead, check the return value of the init... method or factory method you're calling, for example:
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
if (data == nil) {
// Handle failure. It's safe to use the error object here.
}
However, your code doesn't appear to be doing anything with the NSError instance, (e.g., logging, or displaying an alert), so you can just pass NULL instead.
NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
if (data == nil) {
// Handle failure.
}
I am new to iOS. I have this JSON data that I needed to parse:
{
"allseries":[
{
"type":"HR",
"title":"Heart Rate",
"xLabel":"Time",
"yLabel":"Beats per Min",
"defaultUnit":"BPM",
"url":"info/info?user=admin%40korrent.com&type=HR",
"size":18,
"firstTs":1406755651,
"lastTs":1406841254
},
{
"type":"TEMP",
"title":"Temperature",
"xLabel":"Time",
"yLabel":"Temperature",
"defaultUnit":"F",
"url":"info/info?user=admin%40korrent.com&type=TEMP",
"size":6,
"firstTs":1406854147,
"lastTs":1406854283
}
],
"status":"OK"
}
So far this is my code:
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#"--> async response data (string): %#", dataReceived);
NSData *jsonData = [dataReceived dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:&jsonError];
NSLog(#"JSON key and value %#", [dict description]);
NSLog(#" %# ", dict[#"allseries"]);
NSString *jsonString=dict[#"allseries"];
if (_programState == 4){
NSLog(#"state is 4");
NSLog(#"%#",jsonString);
NSData *Data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
However, the code throws invalid argument exception for this line:
NSData *Data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
Further more, jsonString seems totally "inoperable". I cannot split it, append strings to it etc. So what's wrong?
// The following two lines are just for logging and otherwise are not needed.
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#"--> async response data (string): %#", dataReceived);
// Deserialize the JSON data into a dictionary
NSError *jsonError;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData: _responseData options:nil error:&jsonError];
NSLog(#"JSON key and value %#", dict);
// Get the array from the dictionary element "allseries".
NSArray *jsonArray = dict[#"allseries"];
NSLog(#"jsonArray: %#", jsonArray);
Here jsonArray is the array of dictionaries for "allseries" from the JSON
What you did is totally, totally wrong.
dict[#allseries] is not an NSString. It is an NSArray with two elements, and both its elements are NSDictionary.
NSLog(#"%#", request.responseString);
This gives me output of {"errors":{"email":["is already taken"]}}.
I would like to save email and the message string "is already taken" into a string to display in an alert. How can I access those two items into two strings?
The response string is the raw output from the server. In this case it is JSON encoded. You can either use one of the AFNetworking JSON-specific classes (i.e. AFJSONRequestOperation) to get the response back as a JSON object, or parse it yourself using NSJSONSerialization. I would suggest using AFJSONRequestOperation.
NSData *data = [request.responseString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *str = [[json objectForkey:#"errors"] objectForKey:#"email"][0];
I used the following, seems a tiny bit more robust:
[requestOperation setCompletionBlockWithSuccess:success failure:^(AFHTTPRequestOperation *operation, NSError *error) {
id response = error.userInfo;
if (response && [response isKindOfClass:[NSDictionary class]]) {
NSDictionary *responseDictionary = (NSDictionary *)response;
// AFNetworking hides the actual error response under this key
if ([responseDictionary valueForKey:NSLocalizedRecoverySuggestionErrorKey]) {
id suggestedRecovery = [responseDictionary valueForKey:NSLocalizedRecoverySuggestionErrorKey];
if ([suggestedRecovery isKindOfClass:[NSString class]]) {
// Try to json decode string
id json = [NSJSONSerialization JSONObjectWithData:[suggestedRecovery dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
if (json && [json isKindOfClass:[NSDictionary class]]) {
responseDictionary = json;
}
}
}
// .. extract error message out of responseDictionary
}
}];
NSData *responseData = [[error userInfo] objectForKey:#"data"];
if ([responseData length] > 0)
{
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", str);
}
I have a WebService, which give me the fallowing Json-String back:
"{\"password\" : \"1234\", \"user\" : \"andreas\"}"
I call the webservice and try to parse the returned data like:
[NSURLConnection sendAsynchronousRequest: request
queue: queue
completionHandler: ^(NSURLResponse *response, NSData *data, NSError *error) {
if (error || !data) {
// Handle the error
} else {
// Handle the success
NSError *errorJson = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &errorJson];
NSString *usr = [responseDict objectForKey:#"user"];
}
}
];
But the resulting NSDictionary looks like:
What has the effect, that I cannot get the values - for example user.
Can someone help me, what I am doing wrong? - Thank you.
From the debugger screenshot is seems that the server is (for whatever reason) returning
"nested JSON": responseDict[#"d"] is a string containing JSON data again, so you have to
apply NSJSONSerialization twice:
NSError *errorJson = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData: data options:0 error: &errorJson];
NSData *innerJson = [responseDict[#"d"] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *innerObject = [NSJSONSerialization JSONObjectWithData:innerJson options:NSJSONReadingMutableContainers error:&errorJson];
NSString *usr = [innerObject objectForKey:#"user"];
If you have the option, a better solution would be to fix the web service to return
proper JSON data.