获取缓存的图像不起作用

时间:2015-06-02 08:25:13

标签: ios objective-c uitableview caching image-caching

我试图在我的应用中加载和缓存图像,以便在UITableView上显示。 原始概念如下:

if (image in cache){
    show cached image;
}else{
   if (image in file){
     show filed image;
   }else{
      load image from web asynchronously;
      if (finished){
         store in cache;
         store in file;
      }
   }  
}

这是我为处理图像存储而创建的整个类:

ImageStore.h

@interface ImageStore : NSObject

@property (nonatomic, strong) NSCache *imageCache;

+ (ImageStore*)sharedImageStore;
//cache
- (void)writeImage: (UIImage*)image ToCacheForKey: (NSString*)imageURL;
- (UIImage*)readImageFromCacheForKey: (NSString*)imageURL;
- (BOOL)imageCachedForKey: (NSString*)imageURL;
//file
- (BOOL)writeImage: (UIImage*)image ToPlistFileForKey: (NSString*)imageURL;
- (UIImage*)readImageFromPlistFileForKey: (NSString*)imageURL;
- (BOOL)imageFiledInPlistForKey: (NSString*)imageURL;
@end

ImageStore.m

#import "ImageStore.h"

@implementation ImageStore
static ImageStore* sharedImageStore;
NSMutableDictionary* plistDictioary;

+(ImageStore*)sharedImageStore
{
    if (sharedImageStore == nil){
        sharedImageStore= [[self alloc] init];
    }
    return sharedImageStore;

}

+(id)alloc
{
    {
        NSAssert(sharedImageStore == nil, @"second singleton");
        sharedImageStore = [super alloc];

        return sharedImageStore;
    }

    return nil;
}

-(id)init
{
    self = [super init];
    if (self != nil)
    {
        _imageCache = [[NSCache alloc] init];
    }

    return self;
}

#pragma mark - Cache
- (void)writeImage:(UIImage *)image ToCacheForKey:(NSString *)imageURL{

    if(image != nil){
        [_imageCache setObject:image forKey:imageURL];
    }else{
        NSLog(@"NIL image:%@ ",imageURL);
    }
}

- (UIImage *)readImageFromCacheForKey:(NSString *)imageURL{

    return [_imageCache objectForKey:imageURL];
}

- (BOOL)imageCachedForKey:(NSString *)imageURL{

    if ([_imageCache objectForKey:imageURL] == nil)
    {
        return false;
    }

    return true;

}

#pragma mark - File
- (BOOL)writeImage:(UIImage*)image ToPlistFileForKey: (NSString*)imageURL{

    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:image];
    if (plistDictioary == nil) {
        plistDictioary = [NSMutableDictionary new];
    }
    [plistDictioary setObject:data forKey:imageURL];

    BOOL didWriteSuccessfull = [plistDictioary writeToFile:[self getPlistFilePath] atomically:YES];
    return didWriteSuccessfull;

}

- (UIImage *)readImageFromPlistFileForKey:(NSString *)imageURL{

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[self getPlistFilePath]];
    NSData * data = [dict objectForKey:imageURL];
    UIImage * image = [UIImage imageWithData:data];
    return image;

}

- (BOOL)imageFiledInPlistForKey:(NSString *)imageURL{

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[self getPlistFilePath]];
    if ([dict objectForKey:imageURL] == nil) {

        return NO;
    }else{

        return YES;
    }

}

- (NSString*)getPlistFilePath{

    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentsDirectory = [paths objectAtIndex:0];
    NSString * path = [documentsDirectory stringByAppendingPathComponent:@"Images.plist"];
    return path;
}
@end
tableView:cellForRowAtIndex中的

实施

if ([[ImageStore sharedImageStore]imageCachedForKey:[[dataArray objectAtIndex:indexPath.row] objectForKey:@"image"]]) {
  //cache
  NSLog(@"cached");

  cell.image = [[ImageStore sharedImageStore] readImageFromCacheForKey:[[dataArray objectAtIndex:indexPath.row] objectForKey:@"image"]];

}else{

  NSLog(@"nothing cached");

  if ([[ImageStore sharedImageStore] imageFiledInPlistForKey:[[dataArray objectAtIndex:indexPath.row] objectForKey:@"image"]]) {
     //plist file

     cell.image = [[ImageStore sharedImageStore] readImageFromPlistFileForKey:[[dataArray objectAtIndex:indexPath.row] objectForKey:@"image"]];
  }else{
     //loading with UIImage category async method (see below)

     [UIImage loadFromURL:[NSURL URLWithString:[[dataArray objectAtIndex:indexPath.row] objectForKey:@"image"]] completionBlock:^(BOOL succeeded, UIImage *image) {

            if (succeeded){
                cell.image = image;
            }
        }];
    }
}

修改

下载存储在UIImage类别中的图像:

+ (void)loadFromURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                               if ( !error )
                               {
                                   UIImage *image = [[UIImage alloc] initWithData:data];
                                   [[ImageStore sharedImageStore] writeImage:image ToCacheForKey:[url absoluteString]];//write to NSCache
                                   [[ImageStore sharedImageStore] writeImage:image ToPlistFileForKey:[url absoluteString]];//write to Plist
                                   completionBlock(YES,image);

                               } else{

                                   completionBlock(NO,nil);
                               }
                           }];

}

(抱歉长方法命名。)

控制台为每个屏幕上的单元格返回“没有缓存”,有时在检查缓存和文件时滚动会变得断断续续。

我已经尝试了几天方便的缓存,而已经有一堆有用的图像缓存库。很高兴知道我做错了什么!谢谢你的建议。

3 个答案:

答案 0 :(得分:0)

请看下面的链接:

https://github.com/nicklockwood/AsyncImageView

处理异步图像非常棒。

答案 1 :(得分:0)

您可以使用:https://github.com/rs/SDWebImage

它是处理异步图像和轻松获取缓存的最佳库。

答案 2 :(得分:0)

问题出在writeImage:ToPlistFileForKey:方法中。您将图像转换为数据如下:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:image];

但是将数据转换为图像:

UIImage * image = [UIImage imageWithData:data];

这将始终返回nil,因为存档数据的格式为NSPropertyListBinaryFormat_v1_0而不是PNG(或位图格式)。

不应使用[NSKeyedArchiver archivedDataWithRootObject:image],而应使用UIImagePNGRepresentation(image),如下所示:

- (BOOL)writeImage:(UIImage*)image ToPlistFileForKey: (NSString*)imageURL {
    archivedDataWithRootObject:image];
    NSData *data = UIImagePNGRepresentation(image);
    if (plistDictioary == nil) {
        plistDictioary = [NSMutableDictionary new];
    }
    [plistDictioary setObject:data forKey:imageURL];

    BOOL didWriteSuccessfull = [plistDictioary writeToFile:[self getPlistFilePath] atomically:YES];
    return didWriteSuccessfull;
}

UIImagePNGRepresentation函数以PNG格式返回指定图像的数据,然后获得图像[UIImage imageWithData:data]

希望这会对你有所帮助。