how to load xml into memory in faster way? - iphone

I am new to objective-c. I load the whole xml string from server to an nsxml parser like below: but the problem is loding from url to memory takes much more time than parsing it. how can i solve that? (my app is very slow)
xmlString = [[NSMutableString alloc] initWithContentsOfURL:url usedEncoding:&NSUTF8StringEncoding error:&error];
NSData *xmlData = [xmlString dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];

Run your XML Parser in different Thread.(this will not make your parsing faster)
How To Choose The Best XML Parser for Your iPhone Project

Basically NSXMLParser is slow. There is a possibility of finding a better parser for the specific need. A true stream parser might help if you do not need the entire DOM and validation.

Don't use
xmlString = [[NSMutableString alloc] initWithContentsOfURL:url usedEncoding:&NSUTF8StringEncoding error:&error];
Use a network library like ASIHTTPRequest to load the content from a URL and then parse it.
Loading directly from URL like you've done will hang your app till the data is loaded.
Download and install that library as given in the instructions (it's easy), then you can do
{
//in some function
NSURL *url = [NSURL URLWithString:urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous]; //this will load URL in background
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
//parse the XML here
[self parseXML:responseString];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}

You cannot load the xml faster from the url as it totally depends on your internet connection.
To keep your application smooth, you need to parse the xml in another thread. I answered a similar question in the following url
How to handle freezing programm at loading xml from bad url?
Also there are faster XML parser than the defaul NSXMLParser. There is a good introduction about them in the following blog post. So you can use any of these parser in place of NSXMLParser to improve the performance of your application.
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
I hope that it may clarify a little bit of your question.

Related

iPhone Web service Request Timeout

I am having problems in my iphone application due to weak wifi signals. My application uses webservice to retireve data from our server but when Wifi signals are weak the response never comes back and user gets stuck on "Loading..." overlay screen. Finally the application crashes at the end. How can i handle this situation gracefully. Is there a way to set TimeOut for my webservice calls or something like this?
Thanks, Asif.
try to use ASIHTTP lib
http://allseeing-i.com/ASIHTTPRequest/How-to-use
You might want to learn about ASIHTTPRequest as it features much more than the standard CFNetwork api. The code is straight forward, error handling as well:
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
You can set the NSURLConnection timeout and a delegate to respond to connection:didFailWithError: selector. See this S.O. topic.
if your delegate is never being called, this is a somehow known issue.
The only workaround seems to be setting your own NSTimer to fire after some time and cancel the request. It is definitely awkard, but it should not be that complex.
If you are curious about the reason behind the issue with timeout, it seems to be related to the slow starting of the 3G subsystem in an iPhone.

How to download files to iPhone's filesystem?

i would like to download a bunch of pdf's from a website to the iPhone filesystem in my app.
Because i don't want to download the files everytime i start the app.
In the documentation i found a function called "dataWithContentsOfURL" but the sample code didn't help me. Is this the right way, or is there an easier solution?
Can someone give me a tip or two ? ;-)
greets max
I recommend using ASIHTTPRequest, it's well written, documented and easy to use, heres a quick example from one of my applications download class that downloads a JSON file using ASIHTTPRequest:
-(void)downloadJSONData:(NSString *)path destination:(NSString *)destination secure:(BOOL)secure {
if (![self queue]) {
[self setQueue:[[[NSOperationQueue alloc] init] autorelease]];
}
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:destination error:NULL];
NSURL *url = [NSURL URLWithString:path];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
if(secure){
[request addRequestHeader:#"Authorization" value:[NSString stringWithFormat:#"Basic %#",[ASIHTTPRequest base64forData:[[NSString stringWithFormat:#"%#:%#",self.username,self.password] dataUsingEncoding:NSUTF8StringEncoding]]]];
}
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[request setDownloadDestinationPath:destination];
[[self queue] addOperation:request]; //queue is an NSOperationQueue
}
I would take a look at the how-to-use page as it contains everything you need to know.
You're on the right track
-(void)downloadURL:(NSURL *)theUrl toLocalFileURL:(NSURL *)localURL
{
NSData *dlData = [NSData dataWithContentsOfURL:theURL];
[dlData writeToURL:localURL atomically:YES];
}
So just research how NSURLs are created for local and remote objects and you're all set.
Yes you could download files only as you need(Lazy load).
When ever you want access the files. Check in the documents directory for the file. In the second answer it is being specified. Append file name with the douments path. Check If there is a readable file using NSFileManager's isReadableFileAtPath:instance method. if it returns false then initiate downloading the pdf from the website.
Please do care to create a class which downloads file asynchronously. You could use NSURLconnection to initiate the request and its delegate methods to process its content After downloading content write it to documents folder.
If you could create a class for asynchronous download , you could initiate parallel downloads and use maximum use of the bandwidth.
By making asynchronous downloads you could make sure that you application is responsive even while files are getting downloaded.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
Regards ,
Jackson Sunny Rodrigues
Do not use dataWithContentsOfURL: unless you're executing it somewhere other than the main thread. It is a blocking API as well as one that accesses the network. That is a recipe for bad user experience.
Think about this: You use a blocking API to access the network, but the network is down or really slow. The main thread is now blocked, so your user interface is not responding to user interaction. The user gets frustrated and tries to cancel the download using the handy button you put on the UI, but "OH NO!" it doesn't work because the UI is blocked.
Do not use blocking APIs on the main thread.
You should look at the documentation for NSURLConnection and it's asynchronous loading methods for downloading data.
You should use
NSData* pdf_data = [NSData dataWithContentsOfFile: #"file_path"];
where file_path is the path where you've saved your file (it is usually Documents or Library directories).
To save data there use:
[pdf_data writeToFile: #"file_path" atomically: YES];
To get path to your documents directory you can use:
- (NSString *)applicationDocumentsDirectory {
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}

Loading NSMutableDictionary from URL

I'm currently doing this:
NSMutableDictionary *dict = [[NSDictionary alloc] initWithContentsOfURL: [NSURL URLWithString:#"http://mysite/mypage.php"]];
Which is great, apart from when the data being returned is quite large, and it appears to time out. How could I get around this?
Thanks in advance.
I'm not a big fan of using NSDictionary to manage downloads. I'd probably try something like:
NSURL *url = [NSURL URLWithString:#"http://mysite/mypage.php"];
NSURLRequest *request = [NSURLRequest requestWintURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
Now, if data is not NULL then save to local file. Then load the dictionary using the contents of that file using the initWithContentsOfFile: method.
If you still get the timeouts you can try larger timeoutIntervals.
NSURLRequest (or NSMutableURLRequest) and NSURLConnection.
In convenience methods like initWithContentsOfURL you have no control over things like timeouts. They are fine in my cases but it sounds like you will need to use the more low-level NSURLConnection and NSURLRequest to load data from the server. There are many examples on the net.

How can I create a single HTTP Get request for iPhone?

First of all, sorry for my posibly bad english...
I got a surely big stupid question...
In my enterprise have an automatic door system, that is opened with a HTTP GET request to a file.
Example:
http://ipaddress/rc.cgi?o=1,50
Where the o=number indicates the amount of seconds that the automatic door will run.
The is no need for authentification or nothing (that is made by LAN Radius).
So, the question is...
How can I make a single button (for example in the springboard) that when you touch it, runs the GET request?
You thing that it should be possible with NSURLConection ?
Thanks for all
I'm not sure if this is the best way of going about it, but this is how I've achieved something similar in my own app. Just create a new NSData object that hits the required URL, then release it if you don't need to do anything with the returned data:
NSURL *theURL = [[NSURL alloc] initWithString:#"http://ipaddress/rc.cgi?o=1,50"];
NSData *theData = [[NSData alloc] initWithContentsOfURL:theURL];
[theData release];
[theURL release];
Or just create an NSURLConnection to run asynchronously, then you don't have to worry about the UI hanging and if the delegate is set to nil, you can pretty much forget about it after you've run it.
NSURL * url = [NSURL URLWithString:#"http://ipaddress/rc.cgi?o=1,50"];
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
NSURLConnection * theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:nil];
[request release];
[theConnection release];

TTURLResponse is nil

I am trying to implement a simple TTURLRequest in my app. I'm pretty new to the Three20 framework. I mainly want TTURLRequest and TTImageView for the awesome caching stuff.
I have the following code in my delegate:
- (void)requestDidFinishLoad:(TTURLRequest*)request {
TTURLDataResponse *response = request.response;
// Stuff to process response.data
}
response is always nil. I can't figure out what I'm doing wrong. I looked in the Application Support directory and it's creating the cache file with the proper data, so I know it's getting a response. What am I doing wrong?
Debugged your code - you actually have to create a response object and add it to the request before sending your request:
NSString *url = #"http://twitter.com/statuses/user_timeline/samsoffes.json?count=1";
TTURLRequest *theRequest = [[TTURLRequest alloc] initWithURL:url delegate:self];
theRequest.response = [[[TTURLDataResponse alloc] init] autorelease];
[theRequest send];
One would think the request would be in charge of creating the response, but the Three20 stuff doesn't.
Mark Allen from revetkn.com posted a datasource implementation for TTURLRequest.
He also posted an example project where he assumes you have Three20 installed at ../ (relative to your project). It's here: http://revetkn.com/?p=72