I'm trying to send data to a server and receive the response in JSON format. The problem is that the server has to return "success" or "fail" but it returns "(null)".
Here's the returned error:
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=XXXXXXXXX
{NSDebugDescription=JSON text did not start with array or object and
option to allow fragments not set.}
Is it possible that the error is in the server script?
Here's my function to send the data and receive the response:
- (void) putData:(NSString *)parameter valor:(NSString *)valor {
NSString *rawString = [NSString stringWithFormat:#"%#=%#", parameter, valor];
NSData *data = [rawString dataUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:#"http://www.xxx.xxx/xxx.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"PUT"];
[request setHTTPBody:data];
NSURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSLog(#"responseData: %# error: %#", json, error);
}
Unless you pass the option NSJSONReadingAllowFragments to [NSJSONSerialization JSONObjectWithData:options:error:] the response from the server must be valid JSON with a top level container which is an array or dictionary.
for example:
{ "response" : "Success" }
P.S.
If you want a mutable dictionary you must also include NSJSONReadingMutableContainers in your options.
It may possible that, the response from your server doesn't contain valid JSON.
Technically, The JSON object must be start with either an "array" or an "object (dictionary)".
So, Whatever your server is returning isn't.
And, you can force the JSON to be consumed regardless by using the NSJSONReadingAllowFragments option.
by using ,
AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
You can get this issue if you're connected to VPN on your iOS device.
Related
Trying to parse simple JSON data from Instagram but stuck with this problem.
JSON data returns truncated in application, but everything is ok via browser on my mac.
Tried to do that many different ways, but all the same.
First way:
NSURL *instaGetRecentOwnerPhotosURL = [NSURL URLWithString:#"https://api.instagram.com/v1/users/self/media/recent/?access_token=MY_PROPER_TOKEN"];
NSData *jsonData = [NSData dataWithContentsOfURL:instaGetRecentOwnerPhotosURL];
Another way, assync:
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://api.instagram.com/v1/users/self/media/recent/?access_token=MY_PROPER_TOKEN"]];
__block NSDictionary *json;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
NSLog(#"Async JSON: %#", json);
}];
JSON data returns like that:
screenshot of truncated json
Absolutely have no idea what is wrong.
It's not truncated. The log simply only shows part of the output. If it was really truncated it either wouldn't have parsed at all or it would just have fewer entries. But the data did parse. There is nothing wrong with json.
BTW - do proper error checking:
NSError *error = nil;
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (json) {
// Data is good. Work with 'json'
} else {
NSLog(#"Unable to parse JSON. Error: %#", error);
}
I’ve never used an API in conjunction with web services before and I’m having trouble parsing the JSON data I’m receiving from Flickr’s API. The only thing I do know (from all the things I have read) is that it is easy and very simple. About as far as I can get is returning a string in the console. Using a dictionary returns null and or an error. What am I missing? I want to be able to pull out the id and owner so that I can get the photo url.
This returns data on my photo:
NSString *json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#”%#”, json); //this returns data on my photo
This returns null(resultDict) and error 3840:
NSString *requestString = #”https://api.flickr.com/services/rest?&method=......etc;
NSURL *url = [NSURL URLWithString:requestString];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary *resultdict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(#”%#”, resultDict); //returns null
If (error != nil) { NSLog(#”%#”, [error localizedDescription]); }
else { self.myDict = [[resultDict objectforKey:#”photos”] objectAtIndex:0];
NSLog(#”%#”, self.myDict); }
}];
[task resume];
To check if I have an array of dictionaries I did the following and it returned 0:
NSMutableArray *resultArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainer error:&error]; error:&error];
NSLog(#"%lu", (unsigned long)resultArray.count);
Are you sure that
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
returns a Dictionary and not an Array of Dictionnaries?
EDIT :
Can you try to use this to request the API please?
I checked in my projects, my reponses seems to have the same syntax as yours.
Only the code I use is different.
(If you could give us the full URL you've to call, it would be easier for us ^^')
NSString *str=#"YOUR URL";
NSURL *url=[NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error: &error];
NSMutableDictionary* resultList = [NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:nil];
I copied it without the errors. I let you manage that ^^
NSMutableDictionary ***resultdict** = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(#”%#”, **resultDict**); //returns null
resultdict and resultDict are not the same variables. I bet you have an instance variable or a global variable somewhere named resultDict. Instance variables should start with an underscore, among other reasons because it avoids problems like this.
For question maker this answer won't be actual but maybe for them who will face with such problem.
I had the same problem when tried to get data from flickr.photos.getRecent method. I forgot to add into URL parametrs value nojsoncallback=1.
Without it you get response in JSONP.
My json response from a URL is:
[
{"status":0,
"id":"26",
"content":"See info field for info",
"time":1347565292761,
"info": {"id":"26",
"name":"Ruti",
"twitterPageFollowers":null,
"facebookPageLikes":null,
"activeEmailClients":1}
}
]
I need to extract from it the following strings:
twitterPageFollowers
facebookPageLikes
activeEmailClients
How can I do it?
I tried parsing like this
NSData *urlData=[NSURLConnection sendSynchronousRequest:serviceRequest returningResponse:nil error:nil ];
NSString *returnString=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSData *jsonData = [returnString dataUsingEncoding:NSUTF8StringEncoding];
NSArray *json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSDictionary *response = [json objectAtIndex:0];
NSString *info = [response objectForKey:#"info"];
NSData *businessInfoString = [info dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *businessInfo =
[NSJSONSerialization JSONObjectWithData: businessInfoString
options: NSJSONReadingMutableContainers
error: nil];
And the return data is ok, but I get [__NSCFDictionary dataUsingEncoding:unrecognized selector sent to instance for the last NSDictionary creation from info field.
What is wrong or what is the shorter way to retrieve the above fields?
When you retrieve the "info" field using [response objectForKey:#"info"];, you already get an NSDictionary! (and NOT an NSString).
That's why when you try to call dataUsingEncoding: on this object (that you believed was an NSString but is as NSDictionary) you get the exception.
There is no need to retrieve the value of "info" key then converting it to NSData and converting it back a JSONObject, because it is already a JSONObject, namely an NSDictionary in your case. Why bother trying to convert it back and forth, whereas [response objectForKey:#"info"]; already returns that businessInfo dictionary that you expect at the end of your code?
I've read through the questions and answers related to TouchJSON serialization and I'm still not getting it to work.
I create an NSDictionary with sample data and used the JSONTouch serializer to convert the NSDictionary to JSON. However, when I log the NSData object 'theJSONData', it gives me this as a result:
<7b223131 31353535 34343434 223a2250
...
65227d>
Additionally, when I send this 'theJSONData' data to the web service (that's expecting JSON) this is what I get back:
2011-07-31 18:48:46.572 Street Lights[7169:207] Serialization Error: (null)
2011-07-31 18:48:46.804 Street Lights[7169:207] returnData: (null)
2011-07-31 18:48:46.805 Street Lights[7169:207] Error: Error Domain=kJSONScannerErrorDomain Code=-201 "Could not scan array. Array not started by a '[' character." UserInfo=0x4d51ab0 {snippet=!HERE>!?xml version="1.0" , location=0, NSLocalizedDescription=Could not scan array. Array not started by a '[' character., character=0, line=0}
What am I doing wrong? Does the JSON NSData object 'theJSONData' need to be converted to another type before I send it to the web service? Is there another step I'm missing?
// Create the dictionary
NSDictionary *outage = [[NSDictionary alloc] initWithObjectsAndKeys:
#"YCoord", #"12678967.543233",
#"XCoord", #"12678967.543233",
#"StreetLightID", #"666",
#"StreetLightCondition", #"Let's just say 'BAD'",
#"PhoneNumber", #"1115554444",
#"LastName", #"Smith",
#"Image",#"",
#"FirstName", #"Dawn",
#"Comments", #"Pole knocked down",
nil];
NSError *error = NULL;
// Serialize the data
NSData *theJSONData = [[CJSONSerializer serializer] serializeDictionary:outage error:&error];
NSLog(#"theJSONData: %#", theJSONData);
NSLog(#"Serialization Error: %#", error);
// Set up the request and send it
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://24.52.35.127:81/StreetLight/StreetlightService/CreateStreetLightOutage"]];
[request setHTTPMethod: #"POST"];
[request setHTTPBody: theJSONData];
// Deserialize the response
NSData *returnData = [ NSURLConnection sendSynchronousRequest: request returningResponse: nil error:&error];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding: NSUTF8StringEncoding];
NSData *theReturnData = [returnString dataUsingEncoding:NSUTF8StringEncoding];
id theObject = [[CJSONDeserializer deserializer] deserializeAsArray:theReturnData error:&error];
NSLog(#"returnData: %#",theObject);
NSLog(#"Error: %#", error);
Thanks for everyone's help. I ended up using Fiddler to track what needed to be sent to the service in JSON and then saw I hadn't been formatting the header correctly. Here is the code that ended up working for me.
// Create the NSDictionary
NSDictionary *outage = [[NSDictionary alloc] initWithObjectsAndKeys:
#"12.543233",#"YCoord",
#"12.543233",#"XCoord",
#"111",#"StreetLightID",
#"Dented pole",#"StreetLightCondition",
#"1115554444",#"PhoneNumber",
#"Black",#"LastName",
[NSNull null],#"Image",
#"White",#"FirstName",
#"Hit by a car",#"Comments",
nil];
// Serialize the data
NSError *error = NULL;
NSData *theJSONData = [[CJSONSerializer serializer] serializeDictionary:outage error:&error];
NSLog(#"Serialization Error: %#", error);
// Change the data back to a string
NSString* theStringObject = [[NSString alloc] initWithData:theJSONData encoding:NSUTF8StringEncoding];
// Determine the length of the data
NSData *requestData = [NSData dataWithBytes: [theStringObject UTF8String] length: [theStringObject length]];
NSString* requestDataLengthString = [[NSString alloc] initWithFormat:#"%d", [requestData length]];
// Create request to send to web service
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://11.22.33.444:55/StreetLight/StreetlightService/CreateStreetLightOutage"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:requestData];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:requestDataLengthString forHTTPHeaderField:#"Content-Length"];
[request setTimeoutInterval:30.0];
// Deserialize the response
NSData *returnData = [ NSURLConnection sendSynchronousRequest: request returningResponse: nil error:&error];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding: NSUTF8StringEncoding];
NSData *theReturnData = [returnString dataUsingEncoding:NSUTF8StringEncoding];
id theObject = [[CJSONDeserializer deserializer] deserializeAsArray:theReturnData error:&error];
NSLog(#"returnData: %#",returnString);
NSLog(#"Error: %#", error);
For one thing, you've got your objects and keys reversed in the NSDictionary.
I don't know enough about TouchJSON to help with that part of the code.
I am having similar issues in parsing a goodle v3 api response. Still no closer to resolving my issue, but one thing I have found that may be helpful to you is if you are using the deserializerAsArray then the JSON response must be enclose in "[" and "]" and if you are deserializerAsDictionary then the JSON response must be enclosed in "{" and "}".
As the google v3 api JSON response is in the "{" "}" format I need to use deserialiserAsDictionary method.
I suspect you know this already, but after looking at Jonathan Wight's code this is as far as I have come in resolving my own issue as Jonathan's code is specific in checking for the above in parsing the JSON response.
Thanks,
Tim
I have this code
NSString *tr = [self sendUrl:#"http://google.com/"];
But for some reason 'tr' will remain nil after it is executed. What am I doing wrong?
sendUrl :
- (NSString *)sendUrl:(NSString *) uri {
NSLog(#"Requesting URI 1 ...");
// Prepare URL request to download statuses from Twitter
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:uri]];
NSLog(#"Requesting URI 2 ...");
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSLog(#"Requesting URI 3 ...");
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#"Requesting URI 4 ...");
return json_string;
}
Are you absolutely certain that response is not nil? If your request to Google or wherever fails, response will be set to nil and the error will contain some information that will help you diagnose the error so change
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
to
NSError* error = nil;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (response == nil)
{
NSLog(#"request failed with error %#", error);
// any other error handling
}
Next thing. The default encoding for an HTTP message is ISO-8859-1, not UTF-8. According to Apple's docs, -initWithData: will return nil if the encoding is wrong. You probably want NSISOLatin1StringEncoding. I say "probably" because HTTP has a mechanism for telling you what character encoding it used. I think it's the header Content-Transfer-Encoding but I advise you to Google the HTTP RFC to find out for sure.
Finally if json_string were not nil, it would be leaking. Because you obtained it with alloc, you own it which means you need to autorelease it before returning it from sendURL: This last point is not the cause of your problem, it is a separate bug in your code.