I need to mention something before i explain the bugs.
The JSON format is valid, and the code has works fine also.
when i pull the data from the server, the data SOMETIME will got error.
When i try to NSLog the return, and below is the error return.
Error parsing JSON: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Unterminated string around character 2424.) UserInfo=0x956f200 {NSDebugDescription=Unterminated string around character 2424.}
On my Iphone 4, it works fine. But it will always fail to get data Xcode SDK or Iphone 5s, even all is running the same apps.
This this i upload is the return data(just show you how huge data for the return).
NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data > %#",returnString);
SBJsonParser *jsonParser = [SBJsonParser new];
NSError *thiserror;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &thiserror];
parseData = (NSDictionary *) [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &thiserror];
if (!jsonArray) {
NSLog(#"Error parsing JSON: %#", thiserror);
}
On the returnString nslog, it had return the complete data.
On the jsonArray, it always go false, means will display the error
Now i trying to assume because the json is too large, so the connection speed will make the return be error. but i not really got idea how to solve it. Is that i looking on wrong direction? or any one can give me hints how to solve this problem? thanks!
Related
- (NSDictionary*)PostWebService:(NSString*)completeURL param:(NSString*)value
{
#try
{
NSString *urlStr =[completeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
//NSString *urlPart=#"req=value";
//NSString *urlPart;
NSString *urlPart=[NSString stringWithFormat:#"req=%#", value];
NSLog(#"String %#",urlPart);
NSData *requestBody = [urlPart dataUsingEncoding:NSUTF8StringEncoding];
//NSLog(#"String %#",requestBody);
[request setHTTPBody:requestBody];
NSURLResponse *response = NULL;
NSError *requestError = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] ;
NSLog(#"String %#",responseString);
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
return json;
}
#catch(NSException *e)
{
NSLog(#"reason is%#",e.reason);
}
}
and i call this method here..
-(NSDictionary*)gotvall:(NSString*)req
{
#try
{
NSString *vurl=#"some url/";
// vurl=[vurl stringByAppendingString:#"req="];
// vurl=[vurl stringByAppendingString:req];
// NSLog(#"%#",vurl);
NSDictionary *json=[self PostWebService:vurl param:req];
NSLog(#"json is%#",json);
return json;
}
#catch(NSException *e)
{
NSLog(#"%#",e.reason);
}
}
After debugging this method I got result as data parameter is nil.
Can anyone tell that what I am doing wrong here.
I got the complete url and when I run that url on browser I got the perfect data but when I printing the value of json it returns null.
You reported that your error was:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x8d84960 {NSErrorFailingURLStringKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicle/, NSErrorFailingURLKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicle/, NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x8d8bfe0 "unsupported URL"}
That %20 in your error message is a space at the start of your URL that your stringByAddingPercentEscapesUsingEncoding call converted to %20. If you remove that extra space, you should be in good shape.
A couple of other observations:
Just to warn you, your use of stringByAddingPercentEscapesUsingEncoding will correctly handle the presence of a space in the req value. But it will not properly handle the presence of certain other characters (notably & or +). If it's possible that those sorts characters might appear in the req value, you might want to remove the call to stringByAddingPercentEscapesUsingEncoding for the whole URL, and instead just use CFURLCreateStringByAddingPercentEscapes (which gives you a little more control over the percent escaping process) on just the req value. See the percentEscapeString method in this answer: Append data to a POST NSURLRequest.
In both your network request as well as your JSON parsing process, you are returning an NSError object. I might suggest that you log those values if they're ever non-nil, which will help you diagnose problems in the future.
I notice that you are using exception handling. That's not common in Objective-C. As the Programming in Objective-C guide says:
Dealing with Errors
Almost every app encounters errors. Some of these errors will be outside of your control, such as running out of disk space or losing network connectivity. Some of these errors will be recoverable, such as invalid user input. And, while all developers strive for perfection, the occasional programmer error may also occur.
If you’re coming from other platforms and languages, you may be used to working with exceptions for the majority of error handling. When you’re writing code with Objective-C, exceptions are used solely for programmer errors, like out-of-bounds array access or invalid method arguments. These are the problems that you should find and fix during testing before you ship your app.
All other errors are represented by instances of the NSError class. This chapter gives a brief introduction to using NSError objects, including how to work with framework methods that may fail and return errors. For further information, see Error Handling Programming Guide.
Bottom line, As I mentioned in the second point, you should be checking NSError return values yourself rather than relying on exceptions in Objective-C.
-(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 ;)
anyone know how I can handle error code when there is an error on the following:
database_flag = [NSString stringWithContentsOfURL:database_flag_query encoding:NSASCIIStringEncoding error:&error];
TO explain more please find below my code
Basically I want to check mysql for a flag
if the flag is 1 then i get the ip address of the stream from the databse
else i use the local one store.
the only issue is when there is not access to the mysql server the program gets stuck!!
database_flag_query = [NSURL URLWithString:#"http://192.168.0.20/iqkradio_stream_ip_flag.php"];
database_flag = [NSString stringWithContentsOfURL:database_flag_query encoding:NSASCIIStringEncoding error:&error];
database_flag = [database_flag stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([database_flag isEqualToString: #"1"])
{
NSLog(#"URL flag is set");
database_url_query = [NSURL URLWithString:#"http://192.168.0.20/iqkradio_stream_ip_url.php"];
database_url = [NSString stringWithContentsOfURL:database_url_query encoding:NSASCIIStringEncoding error:&error];
database_url = [database_url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
url1 = [NSURL URLWithString:[database_url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(database_url);
}
else
{
NSLog(#"URL flag is not set, Reverting to stored value");
url1 = [NSURL URLWithString: [NSString stringWithFormat: #"http://radio.qkradio.com.au:8382/listen.mp3"]];
}
streamer = [[AudioStreamer alloc] initWithURL:url1];
EDIT - NSURLConnection & Timeouts - Based on the additional information and the comment stream below, and to put information in the answer (rather than the long comment stream):
see accepted answer to this question here for the timeout example. For the NSURLConnection example, checkout the apple documentation here
General Error Handling -
The following link may be helpful --> http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html.
"Before you call this method, you’ll need to create a suitable pointer so that you can pass its address:
NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL
options:0
error:&anyError];
if (!success) {
NSLog(#"Write failed with error: %#", anyError);
// present error to user
}
If an error occurs, the writeToURL:... method will return NO, and update your anyError pointer to point to an error object describing the problem.
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."
So, for your issue, try adding:
if(!database_flag)
{
//call your error handling function
[myFunction withError: error];
}
before trimming the database_flag. If your connection isn't working, then you need to handle it before continueing to your if([database_flag isEqualToString:... code.
If that doesn't solve the problem, can you give some information/log statements on where/what the error is that is halting your application?
Hope that helps.
I have this code here which sometimes works. I make sure that I am connected to the internet before attempting this Get from Twitter, and I am pretty sure it isn't the problem.
...
NSString *twitterURLString = [NSString stringWithFormat:#"https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=twitterapi&count=2"];NSURL *url = [NSURL URLWithString:twitterURLString];
NSError *error = nil;
NSData *dataFromURL = [NSData dataWithContentsOfURL:url
options:0
error:&error];
NSLog(#"%#", error);
...
This returns the following :
Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x4f6520 {NSURL=https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=twitterapi&count=2}
I'm sure it has to do with the url encoding or something since the actual link works well. Also, it actually works sometime, with the same internet connexion (which I repeat is tested and works fine). Any ideas would be greatly appreciated!
Is there a way with NSJSONSerialization to check that the NSData is valid JSON? I don't want the application to error out if the API returns invalid JSON for some reason.
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSError *error;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
This won't "error out", it'll just return nil if the JSON isn't valid. Thus the test to see if it is valid JSON would be:
NSError *error;
if ([NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error] == nil)
{
// Handle error
}
If it does return nil then you can check error to see what went wrong.
NSJSONSerialization Class have a method to do exactly this... (EDIT: no it doesn't...)
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
id jsonObj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
BOOL isValid = [NSJSONSerialization isValidJSONObject:jsonObj];
EDIT: (After hypercrypts' comment)
Hypercrypt is right (I really can't understand how I missed that)...
Even though my answer seems to be working, it's wrong.
What isValidJSONObject: method does is to check if an object can be serialized into JSON and not the other way round. So his answer is what you're looking for. You could use though this method in the case you grab a mutable copy from a json payload, mutate it and later want to check if it's safe to try and re-serialize it back to a JSON string. But bottom line is that hypercrypt's answer is the correct one and I think that it would be more than fair to mark his answer as correct instead of mine. Anyway, sorry about any confusion and #hypercrypt thank's for pointing that out :)
There isn't really a way to check the data without creating the object with NSJSONSerialization; I would put it in a try-catch. If you end up in the catch block, it's not valid JSON.
EDIT: Come to think of it, if it encountered an error, 'error' is an error object. So even if nothing is thrown you can check that to see if the data was valid.