获取缓存图像不起作用
Fetching cached image not working
我试图在我的应用程序中加载和缓存图像以在 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;
}
}
}
这是我为处理图像存储而创建的整个 class:
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);
}
}];
}
(抱歉方法命名太长。)
每个屏幕单元格的控制台 returns "nothing cached",有时在检查缓存和文件时滚动会变得卡顿。
我已经尝试了几天方便的缓存,而已经有一堆有用的图像缓存库。很高兴知道我做错了什么!感谢您的任何建议。
问题出在writeImage:ToPlistFileForKey:
方法中。您将图像转换为如下数据:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:image];
但是像这样将数据转换为图像:
UIImage * image = [UIImage imageWithData:data];
这将始终 return 为零,因为存档数据的格式是 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
函数return获取指定图片的PNG格式数据,得到一张图片[UIImage imageWithData:data]
。
希望对您有所帮助。
我试图在我的应用程序中加载和缓存图像以在 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;
}
}
}
这是我为处理图像存储而创建的整个 class:
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);
}
}];
}
(抱歉方法命名太长。)
每个屏幕单元格的控制台 returns "nothing cached",有时在检查缓存和文件时滚动会变得卡顿。
我已经尝试了几天方便的缓存,而已经有一堆有用的图像缓存库。很高兴知道我做错了什么!感谢您的任何建议。
问题出在writeImage:ToPlistFileForKey:
方法中。您将图像转换为如下数据:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:image];
但是像这样将数据转换为图像:
UIImage * image = [UIImage imageWithData:data];
这将始终 return 为零,因为存档数据的格式是 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
函数return获取指定图片的PNG格式数据,得到一张图片[UIImage imageWithData:data]
。
希望对您有所帮助。