loading big xml file - objective-c

i'm trying to load big file from server, but when it's loading always very slow.
Can you suggest me method, how to fast load more, then 200k objects ?
Printing description of data:
(NSData *) data = 0x08e51d80 151341098 bytes
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (error)
{
NSLog(#"Error,%#", [error localizedDescription]);
}
else
{
NSLog(#"%#", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
}
}];

Two points:
You can use file output stream for network request instead of holding the whole NSData in memory. For example, AFNetworking supports such option.
You can use a SAX parser with stream support for deserialising your data from file, to, again, avoid loading whole XML into memory. For example, NSXMLParser does support stream parsing.
Here's the example of setting up NSXMLParser:
NSInputStream *fileStream = [NSInputStream inputStreamWithURL:temporaryXMLFileURL];
NSXMLParser *parser = [[NSXMLParser alloc] initWithStream:fileStream];
parser.delegate = yourParserDelegate;
BOOL result = [parser parse];
You can implement your parsing & object instantiation code in a class adopting NSXMLParserDelegate, there're a lot of examples over the internet, even one from Apple.
Please keep in mind that all this tricks won't speed up downloading of your large file from the internet, it depends entirely on your connection speed. My approach would only help to reduce your application memory footprint (hence reducing the risk of your app being jettisoned by iOS because of memory pressure).

Switch to JSON. JSON will load and parse MUCH faster than XML. I have a JSON file that is 1.8 MB and it downloads and parses (I use AFNetworking for the connection) in around 7 seconds. Another tip, cache the resulting NSArray on the device so that the next time, you can load directly from that cached array and in the background request the file again and compare to the cached Array. If different, update the model with the new data.
Something like this:
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
NSError *error = nil;
id jsonObj = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
}
}
else {
NSLog(#"Error,%#", [error localizedDescription]);
}
}];

Related

Instagram API json data is truncated via app but ok in browser

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);
}

NSCachedURLResponse ignores HTTPBody

I'm creating a NSMutableURLRequest using this code:
NSString *urlString = #"http://192.168.1.111/api";
NSURL *url = [NSURL URLWithString:urlString];
NSString *postBody = [NSString stringWithFormat:#"param=%#", param];
NSData *postBodyData = [postBody dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postBodyLength = [#( postBodyData.length ) stringValue];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
request.URL = url;
request.HTTPMethod = #"POST";
request.HTTPBody = postBodyData;
request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
[request setValue:postBodyLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
and this code to make the request:
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (cachedResponse && cachedResponse.data.length > 0) {
NSError *serializationError = nil;
id cachedResponseData = [NSJSONSerialization JSONObjectWithData:cachedResponse.data options:0 error:&serializationError];
if (!serializationError) {
NSLog(#"WEB: %#:%# cachedResponseData: %#", NSStringFromClass([self class]), NSStringFromSelector(_cmd), cachedResponseData);
[self showTranslations:cachedResponseData forWords:queryStrings withCallback:completion];
}
} else {
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
requestOperation.responseSerializer = [AFJSONResponseSerializer serializer];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"WEB: %#:%# responseObject: %#", NSStringFromClass([self class]), NSStringFromSelector(_cmd), responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"WEB: %#:%# error: %#", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error);
}];
[[NSOperationQueue mainQueue] addOperation:requestOperation];
}
If I first run it with the param variable equal to "first", if goes through the else block and makes the request. On a second run, it goes through the if block and retrieves the response data from cache. But if I run it again with the param variable equal to "second", it goes through the if block again and retrieves from cache the value coresponding with the first request. How can I make it work like it should and realize that's a different request and not take it from cache?
AFNetworking may be doing something strange; I can only tell you how to handle it with the native APIs, so this may or may not be perfectly correct in your case.
If memory serves, POST requests are not typically retrieved from the cache by the operating system, because they are not considered idempotent. So if you're seeing caching, it is probably happening somewhere outside your device such as a web proxy.
With that said, specifying NSURLRequestReloadIgnoringCacheData should prevent it from using cached data. Or you can prevent it from getting stored in the cache at all by writing a custom cache handling callback and returning nil instead of an NSCachedURLResponse object.
But the real problem here is that you're querying the cache directly instead of letting the OS handle it. The cache has no notion of request types or POST bodies. It is just looking at the URL. If you really want to cache POST requests for some reason, you'll have to concatenate the URL and the body data in some consistent way, then create a new request object for that modified URL, and use the concatenated request object when adding data to and retrieving data from the cache.

How to read Java generated JSON data from Objective C?

I have generated JSON data from Java Restful WebServices and I need to put into the Objective C code. How can I use the JSON data and integrate into Objective C? The IDE has generated the local URL, how can I use the generated JSON data in other machine. Thank you
Have a look at NSURLConnection to retrieve the JSON from your web service. Then you can make use of NSJSONSerialization to parse it.
Use any of the many JSON parsers available. This question compares a few of them: Comparison of JSON Parser for Objective-C (JSON Framework, YAJL, TouchJSON, etc)
You can request the NSData from the URL and then use NSJSONSerialization to interpret it. For example:
NSURL *url = [NSURL URLWithString:#"http://www.put.your.url.here/test.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"%s: sendAsynchronousRequest error: %#", __FUNCTION__, error);
return;
}
NSError *jsonError = nil;
NSArray *results = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(#"%s: JSONObjectWithData error: %#", __FUNCTION__, jsonError);
return;
}
// now you can use the array/dictionary you got from JSONObjectWithData; I'll just log it
NSLog(#"results = %#", results);
}];
Clearly, that assumed that the JSON represented an array. If it was a dictionary, you'd replace the NSArray reference with a NSDictionary reference. But hopefully this illustrates the idea.

App crashes on slow InternetConnection

I am getting data from server in applicationDidBecomeActive method.When net connection is too slow app keep crashing.I do not know how to handle this problem.any help will be appreciated.thanks in advance.
NSString *post =[[NSString alloc] initWithFormat:#"=%##=%#",myString,acMobileno];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http:///?data=%#&no=%#",myString,acMobileno]];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSError *error1 = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string;
if ([response statusCode] >=200 && [response statusCode] <300)
{
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
It's probably crashing because the connection has started downloading, but it hasn't finished therefore allowing the complier to pass your if statement, which would inevitably give a nil urlData parameter.
To fix this, you should be checking to see if there is an error, and then the response headers for the download. Also, I recommend running this operation on a background thread so that it doesn't block the user experience - at the moment, the app will have a delayed launch depending on the size of your file, and the user's download speed.
NSError *error1 = nil;
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string = nil;
if (error != nil && ([response statusCode] >=200 && [response statusCode] <300)){
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
else {
NSLog(#"received error: %#", error.localizedDescription);
}
For a background thread, run the above code in a dispatch_async statement, or use -sendAsynchronousRequest: instead of -sendSynchronousRequest.
Alternatively, as #Viral said, it is possible that the request is taking too long, and the app is hanging as a result of the synchronous request not finishing before the UI should have been loaded.
Most probably, it's due to synchronous call in Application's delegate method. It is taking too much time to load the UI (As internet connection is slow and you are calling the web service on main thread); and therefore OS thinks your App has hanged due to unresponsive UI and crash the App itself.
Just for debugging purpose, try the same code in your FirstViewController's viewDidAppear method. It should work fine there. And if it is so, you need to change your call to somewhere else (also, preferably in some background thread, OR Async).
EDIT: Though, If it works elsewhere, you need to change the call as Async OR on background thread for smoother UX.

Store JSON iTunes Search API data

How can I use the iTunes search API from within iOS/Obj-c ?
I know of this link of course..
http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html
I just don't understand how you use obj-c/iOS with it.
I want to be able to read the JSON results, whether they be broad or just 1 result and store the apps name (or would that be ID?), any images, rating etc in my server database (using parse.com).
How can I do that, and is that allowed by the Apple developer terms?
It looks like you just make the requests and parse the results. No auth or anything else fancy...
NSString *urlString = #"https://itunes.apple.com/search?term=jack+johnson";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
NSError* parseError;
id parse = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&parseError];
NSLog(#"%#", parse);
}
}];
The JSON parser will yield arrays of dictionaries for collection calls and (probably) dictionaries for single objects.