我试图在我的应用中加载和缓存图像,以便在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);
}
}];
}
(抱歉长方法命名。)
控制台为每个屏幕上的单元格返回“没有缓存”,有时在检查缓存和文件时滚动会变得断断续续。
我已经尝试了几天方便的缓存,而已经有一堆有用的图像缓存库。很高兴知道我做错了什么!谢谢你的建议。
答案 0 :(得分:0)
答案 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]
。
希望这会对你有所帮助。