Almacenamiento en caché de imágenes para imágenes en el directorio de documentos

My application download a package with images over HTTP. They are stored in the Documents/ directory, and displayed.

I read that the UIImage didn't work for caching image in the ".../Documents/" directory of the iphone/ipad (because only [UIImage imageNamed:] make use of cache, and it works only for images in the bundle). In addition, I want to be able to clear the cache when I download a new package.

So, here is what I wrote :

In Image.h

#import <Foundation/Foundation.h>

@interface Image : NSObject

+(void) clearCache;

+(UIImage *) imageInDocuments:(NSString *)imageName ;

+(void)addToDictionary:(NSString *)imageName image:(UIImage *)image;

@end

In Image.m

#import "Image.h"

@implementation Image

static NSDictionary * cache;
static NSDictionary * fifo;
static NSNumber * indexFifo;
static NSInteger maxFifo = 25;

+(void)initialize {
    [self clearCache];
}

+(void) clearCache {
    cache = [[NSDictionary alloc] init];
    fifo = [[NSDictionary alloc] init];
    indexFifo = [NSNumber numberWithInt:0];
}

+(UIImage *) imageInDocuments:(NSString *)imageName {
    UIImage * imageFromCache = [cache objectForKey:imageName];
    if(imageFromCache != nil) return imageFromCache;

    NSString * path = [NSHomeDirectory() stringByAppendingPathComponent:[NSString     stringWithFormat:@"/Documents/%@", imageName, nil]];
    UIImage * result = [UIImage imageWithContentsOfFile:path];
    [self addToDictionary:imageName image:result];
    return result;
}

+(void)addToDictionary:(NSString *)imageName image:(UIImage *)image {

    NSMutableDictionary *mFifo = [fifo mutableCopy];
    NSString * imageToRemoveFromCache = [mFifo objectForKey:indexFifo];
    [mFifo setObject:imageName forKey:indexFifo];
    fifo = [NSDictionary dictionaryWithDictionary:mFifo];
    // indexFifo is like a cursor which loop in the range [0..maxFifo];
    indexFifo = [NSNumber numberWithInt:([indexFifo intValue] + 1) % maxFifo];

    NSMutableDictionary * mcache = [cache mutableCopy];
    [mcache setObject:image forKey:imageName];
    if(imageToRemoveFromCache != nil) [mcache removeObjectForKey:imageToRemoveFromCache];
    cache = [NSDictionary dictionaryWithDictionary:mcache];
}

@end

I wrote it to improve performance on loading image. But I'm not sure with the implementation. I wouldn't like to have the opposite effect :

  • There is a lot of recopy (from mutable dictionay to unmutable and the opposite)
  • I don't know how to choose the right maxFifo value.
  • Do you think I need to handle memory warning and clear the cache when it happens ?

What do you think ? is it awkward ?

ps : I put the code on gist.github : https://gist.github.com/1719871

preguntado el 01 de febrero de 12 a las 22:02

Oh, I corrected some errors. The cache was not used at all (missing call to addToDictionary). And this hilighted other errors. -

1 Respuestas

Whoa... are you implementing your own object cache? Have you first taken a look at NSCache to see whether it suits your needs?

(I don't believe UIImage conforms to NSDiscardableContent, so you would have to either purge the cache yourself or wrap UIImage if you want the cache to handle low-memory conditions. But as you note in your question, your current implementation doesn't do that either.)

Respondido 02 Feb 12, 02:02

Thanks, I didn't know about NSCache. I will make some tests with it. Instead of wrapping UIImage maybe I could : 1) Wrap NSCache in my Image class. 2) So I can remove my 2 NSDictionary(and nsinteger). 3) when [Image clearCache] is called, just call the NSCache method [x removeAllObjects]. It seems easier to me. - arnaud del.

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.