简体   繁体   中英

iOS: Asynchronously Download Images from Web *unless* they already exists in filesystem?

In my iOS app I'm using Core Data to model a number of entities that exist in a remote Ruby on Rails application. A number of these entities reference the URLs of images stored in S3 which I need to download and store locally on the user's iDevice as needed.

My specific requirements are:

  1. Display the image (in a UITableView usually or on its own) from the local filesystem.

  2. IF the image doesn't exist locally I need to be able to download it in the background (usually there will be two images that need to be downloaded... a thumbnail and an original). A default image should be displayed until the downloaded image is persisted.

  3. Once the image is downloaded I need to have it saved in the filesystem and displayed on the screen.

I know there are a number of related posts but I'm interested to hear of what you all would consider a recommended approach based on my specific needs. Also, are there any gotchas I need to be wary of?

Thanks -wg

Use ASIHTTPRequest. Read the section on using a download cache here - http://allseeing-i.com/ASIHTTPRequest/How-to-use

Basically you'll want to turn on the cache which you can do for all requests or just your image requests:

[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]]; // all requests

// specific requests
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[ASIDownloadCache sharedCache]];

Then you probably want to use the cache policy:

ASIOnlyLoadIfNotCachedCachePolicy

and the storage policy:

ASICachePermanentlyCacheStoragePolicy

However multiple cache policies would meet your needs.

I'm recommending to use ASI because it solves lots of problems in an app. I recently developed my own network library, partially as an exercise and partially because I did not know about ASI and didn't like the other options I found at the time. I recently started moving everything to use ASI and I'm very happy with my choice

I have a similar requirement for a project I worked on. In my cases I wanted local files when running in test mode but remote files otherwise.

To implement this, I defined a "ResourceURLProvider" protocol within the header file for the class that would be loading the files:

@protocol ResourceURLProvider
    -(NSURL *)getURLForFile:(NSString *fileName);
@end

@interface MyFileLoader {
    id<ResourceURLProvider> provider;
}
@property (nonatomic, assign) id<ResourceURLProvider> provider;

In my implementation class I did something like this:

NSURL *url = [provider getURLForFile:@"myfile.xml"];
if (!url) {
    url = // Some code to create the URL for the remote myfile.xml
}

If you set something up like this then you can implement your version of the provider (whatever you name it) and have it returned a URL to the cached file if it exists. If not, you return nil and the code above will use the URL to the remote location.

Unlike my case, you want to cache the file after you've downloaded it. To do that I might add another method to the protocol I defined:

   @protocol ResourceURLProvider
    -(NSURL *)getURLForFile:(NSString *fileName);
    -(void)cacheFileData:(NSData *)data filename:(NSString *)fileName;
   @end

Your implementation would look at the file name and check to see if the file was already cached. If not, the NSData (the contents of the file) would be written to your cache.

Hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM