NSJSONSerialization - duplicate key error character at (index), char is ":" - json

I created a servlet which responds to get requests with a byte array created from json data. I am trying to consume this data in iOS and use NSJSONSerialization to parse it into a NSDictionary, but it fails with the following error
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Duplicate key for object around character 11.) UserInfo=0x6833200 {NSDebugDescription=Duplicate key for object around character 11.}
Here is my code:
NSString *query = #"http://localhost:8888/url?method=retrieve";
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:query]];
NSError *error = nil;
NSString *stringData = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"substring to index 255: %#", [stringData substringToIndex:255]);
NSDictionary *results = jsonData ? [NSJSONSerialization JSONObjectWithData:[stringData dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error] : nil;
NSLog(#"Response as Dictionary:\n%#", results.description);
if (error) {
NSLog(#"Error: %#", error);
}
the value of stringData is
{"APPEALS":{"APPEAL":{"AppealID":387423483,"LastEdit":"1 . . .
Response as Dictionary returns (null) obviously since there is an error
I am guessing that it has something to do with the fact that my server sends the data in an output stream as a byte[] (java) and it is not formatted correctly as json when received in iOS, but it doesn't make sense to me why it would fail at character 11 ":"
FYI, the server is written on Google App Engine in java and the localhost url is the local dev server. The json data was created using Jackson Generator library. Thanks!

I discovered the answer myself: when the error points to a duplicate key at a ":" character, that means that some key within the following json array is duplicated, not necessarily the one immediately following that character index. From my json data above, I had many "APPEAL" entries, that when turned into an NSDictionary will throw an error since there can be only 1 value for a given key. I believe my confusion arose from reading a Jackson json generator tutorial which described creating entries with the same key so that they can later be serialized into many instances of an object with "key" as the object class name (so I could have created many APPEAL objects using a Jackson parser, but not so in NSJSONSerialization).
I also had concatenated several json files server side:
( {"table":{"title":value}}{"anotherTable":{"title":value}} )
so that my url request response could serve several files with 1 request (cost efficiency), but these had to be split client side and serialized individually since "}}{" isn't legal json format.

The json had a duplicate key.For example,{"json":"3","string":"34","json":"3"}.The json can't be parsed before iOS6.0.

Related

JSON couldn’t be read from URL because it isn’t in the correct format [duplicate]

This is a really weird bug, when grabbing JSON from my server (which is produced via PHP), I get this error when calling:
json = [NSJSONSerialization JSONObjectWithData:kivaData
options:kNilOptions
error:&jsonError];
JSON Error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Garbage at end.) UserInfo=0x178467d00 {NSDebugDescription=Garbage at end.}
My (NSData* kivaData) grabs everything perfectly, but it cant parse the JSON.
I have run my JSON code in http://jsonlint.com/ and it comes out Valid everytime.
Its really weird because it can parse the JSON when I connect to Wifi, but when I try doing it via cellular, it wont work. It does work over cellular on some peoples phones, but every time.
using swift 4, first of all check the JSON Data using print :
print (String(data:data!, encoding: .utf8)!)
check for the white spaces or unwanted characters, then remove them :
var string = String(data: data!, encoding: .utf8)
string = string?.replacingOccurrences(of: "/r/n", with: "")
after that, assign the string back to data variable :
let data1 = string!.data(using: .utf8)
encoding is very important. If your json is valid, the issue might be you have special characters in your json data, which is not correctly parsed by the json serializer. When you send the data, make sure you have the correct url-encoding when sending content so client will parse it correctly. Using utf-8 always or base64.
I was able to solve the same problem (works on wifi, but not on carrier network) by sending a content-length header just before the response:
header("Content-length: ".strlen($response));
echo $response;
exit;
I ended up having to change my php file from echoing the json syntax to simply outputting with json_encode.
JsonData is usually stored in dictionary format. Since the json is not able to parse the continuous data[its not able to separate the responses] its throwing this error .
You can maintain a dictionary to store the responses obtained from server .
Each task will have a unique response . So create a dictionary with "keys" as "taskIdentifier" of tasks and "values" as "data".
Eg:
Inside didReceiveData or any other equivalent methods [where you get response from server ] store response in dictionary with taskIdentifier as keys .
NSString *taskID = [#(dataTask.taskIdentifier) stringValue];
[_task_data_dictionary setObject:data forKey:taskID];
Here _task_data_dictionary is the dictionary.In this way you can get rid of the above error .
After this you can get data using the same dictionary using this code
NSData *data = [_task_data_dictionary objectForKey:taskNumber];
again using the taskIdentifier .
Hope this helps .

Swift json parsing error: Could not cast value of type NSCFConstantString to NSArray

I have some problems with parsing json using swift code.
json example
{"responce": "ok","orders": [{"id":"1"), {"id":"2"}, {"id":"3"} ]}
and this code working fine
let dataArray: NSArray = jsonResult["orders"] as! NSArray
but if I get {"responce": "ok","orders": ""} I got the error: Could not cast value of type __NSCFConstantString (0x10c7bfc78) to NSArray (0x10c7c0470).
Can I somehow check if value is array or not to do not crashed?
Yes you can check if the value is a NSArray by doing this:
if let dataArray = jsonResult["orders"] as? NSArray {
}
If the result of jsonResult["orders"] is a NSArray then dataArray will be set and you will go into the if statement.
This error is most likely caused by the response you are getting back from what I assume is a server not being JSON, but being something like an HTML/XML response saying that the server either could not be reached, or that your query/post request was invalid (hence the fact that the value was an "NSCFConstantString").
Using James' answer is a perfectly good way to check that the value is an Array, but you might want to test your requests using a program like Postman to see what he response is, and then hard code a way to handle that error on the user side.

Understanding xcode json web request

this is my first time connecting an app to the web, I just want to make sure i am clear on how this works.
I want to download data from a mysql db hosted online, it also seems to have php attached (hostgator) is the host.
So steps are:
1. In php (on the server module), set up a method to transcribe mysql information into JSON using the attached PHP module. Return an array (json i think is a mutilayered dictionary array object)
In xcode, use apple's json framework to create a url request, and download data into a json object (or array or dictionary?
Go through the data and create objects and save to coredata.
Please let me know if im following the logic correctly.
Also does JSON return 1 object or all the objects on the mysql db. So if i need to input 10,000 objects on coredata i have to make 10,000 requests or one request and parse 10,000 objects worth of info?
Also is this the best way to do what i need to do? I have heard of http request but it seems complicated, and I have no clue what it is.
Sorry for such a noob question.
Thanks for the help.
There are many ways to do it, some are "more correct" than others :-) but you are on the right way.
I explain what I would do in a similar situation:
1- for the PHP engine, you should create an API to access your data. Which data?
The simpliest and probably the first thing you can do TO TEST (only for testing purpose!!!!) is to create a page that receive a query via POST from your ios APP and answer with an encoded JSON string. With JSON you can transfer an entire hierarchy of objects: variables, arrays, dictionary...is up to you to decide how link the objects together.
If the data you want to encode is a table, you can do something similar to this:
// first connect to the database and execute the query, then...
$data = array();
while(!$RS->EOF){
for ($i = 0; $i < $cols; $i++){
$rowName = utf8_encode($RS->Fields[$i]->name);
$rowValue = utf8_encode($RS->Fields[$i]->value);
$rowData[$rowName] = $rowValue;
}
array_push($data, $rowData);
$RS->MoveNext();
}
$response['data'] = $data;
echo json_encode($response);
the result is a JSON object with a first dictionary with a key named "data".
Inside the "data" key there is an array of dictionaries. Each dictionary has the column name for the key, and the column value for the data:
data = (
{
attivita = "this is the first row in the table";
id = 2548;
},
{
attivita = "this is the second row in the table";
id = 2547;
};
}
You can simply use json_encode to create your json string.
On the iPhone side, I suggest you to download and use AFNetworking. It's a very good and complete open source framework, with a lot of builtin objects and methods for http/https requests, XML, JSON ecc...
Using AFNetworking you can make the request in a similar way:
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:#"http://url.for.the.php.page"];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:mainPath parameters:params];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// your success code here
// remember, the first object is a dictionary with a key called data
NSArray *arrayOfData = [JSON objectForKey:#"data"];
NSMutableArray *arrayOfActivities = [NSMutableArray array];
for (NSDictionary *objectDictionary in arrayOfData) {
// objectDictionary is your dictionary containing
// a key with the column name and a value with the column content
// here you can init your custom objects
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// your failure code here
}];
[operation start];
As you can see, the JSONRequestOperationWithRequest: method has a completion handler returning you the decoded JSON, so you can access your dictionaries/arrays directly using objectForKey or objectAtIndex ;-)
Last suggestions: in a production and secure environment, you should avoid sending query over post requests. The code I pasted here is for a private application (used only by me for testing purpose). It's better to use a different API for each kind of request and a secure authentication method (look at oAuth).
I suggest you to give a look to the Instagram or Twitter API (Instagram is simpler), trying to use it. They will give you some ideas on how to create your own API.
Good luck
Your first step of creating a method to return JSON-ified MySQL data is correct. What exactly is returned however, is completely up to you! You will find that JSON is an extremely flexible format that allows you to put nearly any format of data in your response. It may make sense, depending on what you want to do, to have several methods in your PHP module that return different things. For example, if you have a database of books, maybe you want to create a method that allows you to specify an author, and will return a JSON response with all the books in your database written by that author.
You could use HttpRequest to actually perform the call to your module, but I found the Obj-C NSURLRequest quite easy to use:
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://yoururl/books/38917"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Don't think that you have to manually parse the JSON response into your own Objective-C objects; this is a very common task and there exist many great libraries to do so. Check out this tutorial on the SBJSON framework to view one of the most popular solutions.
As an example, here is how you could parse the JSON response into an NSDictionary for easy traversal:
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming json_string is a NSString of JSON data
NSDictionary *object = [parser objectWithString:json_string error:nil];

How to extract app information from the Apple store?

I'm a newbie with Json, so I want to extract some app information from the app store, I found this question here :
How to get info from the Apple iTunes «App Store» and «Mac App Store»
It allows to get a Json file containing all the app information, but it would be nice if someone could show me how to get the price for example.
Thanks.
Where and how do you want to collect the results? Is this for an app or for some other kind of tool? In the reuslting JSON you have an array "results" where each element has a "currency" and a "price" value. Those can be queired rather simply. For example using the iOS 5 NSJSONSerialization (note this is an example, there has to be more error handling, handling of no / too many entries etc):
// assuming you have the downloaded data
NSError *error = nil;
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:downloadedData options:nil error:&error];
if (error != nil)
{
// error handling
}
else
{
NSArray *results = [jsonData objectForKey:#"results"];
// assuming you have 1 valid entry
NSDictionary *result = [results objectAtIndex:0];
NSNumber *price = [result objectForKey:#"price"];
NSString *currency = [result objectForKey:#"currency"];
NSLog(#"Price is %# #%", price, currency);
}
Similar ways to access the data are avilable in other JSON frameworks, just grad the results array and every dictionary therein has a price and currency value.

How do you parse a JSON array with TouchJSON?

I'm using TouchJSON. Made a call to my Rails app to fetch all "posts" at localhost:3000/posts.json. This returns a JSON array, surrounded by square brackets. I'm currently set up to convert the jsonString into an NSDictionary, but that fails due to the square brackets.
NSString *jsonString=[self jsonFromURLString:#"http://localhost:3000/posts.json"];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
self.dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
What's the best way to turn this result into an NSArray using the TouchJSON library?
Error Domain=kJSONScannerErrorDomain Code=-101 "Could not scan dictionary. Dictionary that does not start with '{' character."
Why don't you just use the -deserialize: method and then figure out what kind of object you have after its done?
Or to answer your specific question, use -deserializeAsArray:
I think most parsers frown with array data. You'll have to return a hash:
{'result': [Your array data]}