I'm using setImageWithURL to download some images in my app. Is it possible:
to specify how long this image must be held in cache (eg 1 week)?
to specify how big the the maximum total size of the cache (eg 200
MB)
to see what is in the image cache?
to clear the cache?
The documentation is not really clear on these points..
The UIImageView category uses an internal, ephemeral cache for high performance in things like UITableView. For longer-term cache, use the system-level cacheing system--namely Peter Steinberger's fork of SDURLCache, a subclass of NSURLCache.
Set it up with the following code in the application delegate applicationDidFinishLaunching:withOptions::
SDURLCache *URLCache = [[SDURLCache alloc] initWithMemoryCapacity:1024*1024*2 diskCapacity:1024*1024*20 diskPath:[SDURLCache defaultCachePath]];
[URLCache setIgnoreMemoryOnlyStoragePolicy:YES];
[NSURLCache setSharedURLCache:URLCache];
[URLCache release];
Related
-(void)setImageWithURL:(NSURL *)url,
the method in AFNetworking described: "If the image is cached locally, the image is set immediately", but it does not make me to set cache directory, so where it cache the image in? Or is it really cache the image?
AFNetworking takes advantage of the caching functionality already provided by NSURLCache and any of its subclasses.
Use Pete Steinberger's fork of SDURLCache which provides disk caching, which is not otherwise implemented by NSURLCache on iOS.
Note: as of iOS5, this is no longer needed. NSURLCache now properly caches objects, as long as the Cache-Control header is set.
You may find it useful to set ignoreMemoryOnlyStoragePolicy to YES for the SDURLCache instance, which will ensure that images will be cached to disk more consistently for offline use (which, as reported in the SDURLCache README, iOS 5 supports, but only for http, so it still remains a good option if you want to support iOS 4 or https)
Refer AFNetworking-FAQ - Does AFNetworking have any caching mechanisms built-in? and also AFURLCache - disk cache for iOS links.
I have setup an NSURLCache and set the sharedcache to the initialized cache.
I can see the cache size growing when I log the size in the NSURLConnection delegates.
For some reason when requesting the same data, a request is made to the server again, and the log of the cache size shows the log staying the same size.
This indicates to me that the cache is working correctly, but for some reason the URL Loader is not pulling from the cache.
I use the default cache policy on the requests and have double checked the headers in the response.
After reading around on here I see other people mentioning the same issue and setting the memory capacity and disk capacity to the same value solves their issue, but it does not work for me. New requests are being made every time rather than pulling from the cache.
Would it be wise to instead check the cache for the data before making the request? I dont see the point of the cachingPolicy parameter to the NSURLRequest method.
well HTTP also lets the server tell you how to cache - it can disallow caching (and also set a max. cache time)
that may influence SDURLCache
anyways, also look at UIWebView and NSURLCache have a troubled relationship
there it is said that UIWebView doesnt work
I'm in the process of building a data store for keeping track of all the remote images being stored in my app. I've decided to use a singleton that will keep track of all the images being referenced.
As I remember, iOS automatically begins purging objects from memory based on recency of usage, whether or not it's being referenced by the current view controller, etc. However, if I store these images in a data store, those objects are always being referenced by the store itself. My solution for memory management was to keep track of when images were last called and keep some form of limit on the # and size of images being stored in the data store and purge the oldest based on age.
Is this solution a good one? Why or why not? Should I be depending on Apple's automatic memory management, or is having my own manager fine?
Further explanation:
Here's how requesting an image from one of my view controllers will end up looking with my solution:
[[HollerImages store]getImageWithUrl:#"https://www.google.com/logos/classicplus.png"
completionBlock:^(BOOL succeeded, UIImage *image){
if( succeeded ){
//Update the UIImageView with the returned image
}
}];
The store will then manage how many images are currently being referenced in the app and automatically de-reference old images as we hit some pre-defined limit. Thoughts?
Renaud Boisjoly (#rboisjoly) just sent me a link to this library which appears to provide the solution I was describing: https://github.com/rs/SDWebImage/
The easiest way to handle memory concerns is to just implement the -(void)didReceiveMemoryWarning function and clear out all your cached data there.
What you're talking about is implementing an expiring cache. You could just count the elements in your data structure at each insertion and remove elements from the head when you've hit the limit (provided it is an ordered data structure). The former solution is easier and works in most cases.
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:
Display the image (in a UITableView usually or on its own) from the local filesystem.
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.
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.
I have a CherryPy app that dynamically generates images, and those images are re-used a lot but generated each time. The image is generated from a querystring containing the variables, so the same query string will always return the same image (until I rewrite the generation code) and the images are not user-specific.
It occurred to me that I should be aggressively caching those images, but I have no idea how I would go about doing that. Should I be memoizing in CherryPy? Should I do something like this for Apache? Another layer entirely?
Your first attempt should be to use the HTTP cache that comes with CherryPy. See http://docs.cherrypy.org/dev/refman/lib/caching.html for an overview. From there, it's usually a "simple" matter of balancing computational expense versus RAM consumption via cache timeouts.