How to download files to iPhone's filesystem? - iphone

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

Related

Xcode UIWEBVIEW download , save HTML file and show

I want to download a page and show this in WEBVIEW local, but the images are missing. The images are only shown, when I'm online, in offline mode they are missing. How can I solve this? This is the code I used up until now:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
NSURL *url = [NSURL URLWithString:#"http://livedemo00.template-help.com/wt_37587/index.html"];
//[WEBVIEW loadRequest:reqURL];
// Determile cache file path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0],#"index.html"];
// Download and write to file
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
// Load file in UIWebView
[WEBVIEW loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
[super viewDidLoad];
}
I've been meaning to write this up for a few weeks now, and this question finally got me to do it. See Drop-in offline caching for UIWebView (and NSURLProtocol).
The short answer, in my experience, is that the easiest solution is to use an NSURLProtocol to intercept NSURLConnection requests (including the ones made by UIWebView) and write the results to disk. If the request is made when you're offline, just read the response from disk and replay it. This is extremely transparent to the rest of the application, and avoids all kinds of edge-cases related to subclassing NSURLCache. (For more information on how to subclass NSURLCache see Substituting local data for remote UIWebView requests on Cocoa With Love, and AFCache.)
My NSURLProtocol approach is very simple, and is not a general-purpose caching solution. It's just intended to assist a UIWebView when you're offline. But for that, I think it solves the problem well.

how to load xml into memory in faster way?

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.

how do i remove coredata from iphone

You know how you can Reset the coredata store on an iPhone simulator when you've changed your entity structure?
Do I need to perform a similar process when I've created a new version of my core data store that is different from what I last ran on my iPhone? If so, how, please?
Thanks
Just for convenience, until you code a way to remove the persistent store through your app, you can just delete the app off the phone. (Hold your finger on the home screen until icons get wiggly, then click the x on your app.) Then with your phone connected to your Mac, choose Product > Run in XCode and it will reinstall your app on the phone, but with empty data directories.
For deployment, of course, you need to come up with a way to do it without deleting the app, if you will ever change your data model after deployment (assume you will). Data migration is the best option, but if all else fails delete the persistent store file. It would be preferable to prompt for the user's approval before doing that. If they have important data they can decline and maybe get the old version of your app back to view the data and migrate it by hand, or they can wait until you release version 2.0.1 that fixes your data migration bug.
Here is the routine I use to reset my App content. It erases the store and any other file stored.
- (void) resetContent
{
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSString * rootDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *rootURL = [NSURL fileURLWithPath:rootDir isDirectory:YES];
NSArray *content = [localFileManager contentsOfDirectoryAtURL:rootURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants error:NULL];
for (NSURL *itemURL in content) {
[localFileManager removeItemAtURL:itemURL error:NULL];
}
[localFileManager release];
}
If you only want to erase the store, since you know its file name, you can refrain from enumerating the document directory content:
- (void) resetContent
{
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSString * rootDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *rootURL = [NSURL fileURLWithPath:rootDir isDirectory:YES];
NSURL *storeURL = [rootURL URLByAppendingPathComponent:#"myStore.sqlite"];
[localFileManager removeItemAtURL:storeURL error:NULL];
[localFileManager release];
}
But please note that in many cases, its better to migrate your store when you change your model, rather than to delete it.
locate your app in /Users/username/Library/Application Support/iPhone Simulator/4.3.2 (iOS Version may be different) and delete the .sqlite file
You can look at the path that is being sent to the persistentStoreCoordinator on setup, and remove that file. Usually the approach I have taken is that I set up the store to auto migrate, and if that fails I delete the store and attempt one more time to create the persistentStoreCoordinator which will use the now empty path.
Don't forget you may need to repopulate anything stored in the old database.

how to cache a whole web page with images in iOS

I am working on a image-text mixture page on iOS. I know it is possible for me to use UIWebView to achieve the goal. But the problem is, user may need to read the page offline.
For the text part, I can save the html to the disk and load it in the offline mode.
But how about images? Is it possible to cache the images to the disk and the UIWebView can still be able to display them?
Thank you!
The ASIHTTPRequest project has a class called ASIWebPageRequest which is designed to do exactly what you want. If you're okay with adding an additional dependency to your project then I think it's a good solution for you: ASIWebPageRequest.
On the page I liked above there are some good examples of how to use it but I'll include one of them here for completeness:
- (IBAction)loadURL:(NSURL *)url
{
// Assume request is a property of our controller
// First, we'll cancel any in-progress page load
[[self request] setDelegate:nil];
[[self request] cancel];
[self setRequest:[ASIWebPageRequest requestWithURL:url]];
[[self request] setDelegate:self];
[[self request] setDidFailSelector:#selector(webPageFetchFailed:)];
[[self request] setDidFinishSelector:#selector(webPageFetchSucceeded:)];
// Tell the request to embed external resources directly in the page
[[self request] setUrlReplacementMode:ASIReplaceExternalResourcesWithData];
// It is strongly recommended you use a download cache with ASIWebPageRequest
// When using a cache, external resources are automatically stored in the cache
// and can be pulled from the cache on subsequent page loads
[[self request] setDownloadCache:[ASIDownloadCache sharedCache]];
// Ask the download cache for a place to store the cached data
// This is the most efficient way for an ASIWebPageRequest to store a web page
[[self request] setDownloadDestinationPath:
[[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:[self request]]];
[[self request] startAsynchronous];
}
- (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest
{
// Obviously you should handle the error properly...
NSLog(#"%#",[theRequest error]);
}
- (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
{
NSString *response = [NSString stringWithContentsOfFile:
[theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
// Note we're setting the baseURL to the url of the page we downloaded. This is important!
[webView loadHTMLString:response baseURL:[request url]];
}

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];