缓存 URL 图片 iphone UITableview

Posted

技术标签:

【中文标题】缓存 URL 图片 iphone UITableview【英文标题】:Cache URL images iphone UITableview 【发布时间】:2010-02-15 10:05:46 【问题描述】:

我正在寻找有关如何将从 url 加载的图像缓存到 uitableview 的单元格中的教程。

我在这里找到了一个例子

http://www.ericd.net/2009/05/iphone-caching-images-in-memory.html#top

但代码不完整。我是一个客观的新手,所以我发现填补缺失的部分非常困难。

【问题讨论】:

您可以使用 UIImageLoader (github.com/gngrwzrd/UIImageLoader) 或 SDWebImage 之类的帮助程序,而不是自己实现所有内容。 UIImageLoader 只有两个文件,使用起来超级简单。 repo 中也有一个很好的示例。 【参考方案1】:

这是一个使用 NSCache 的简单 ImageCache 实现。 ImageCache 是一个单例。

ImageCache.h

    #import <Foundation/Foundation.h>

    @interface ImageCache : NSObject

    @property (nonatomic, retain) NSCache *imgCache;


    #pragma mark - Methods

    + (ImageCache*)sharedImageCache;
    //- (void) AddImage:(NSString *)imageURL: (UIImage *)image;
   - (void) AddImage:(NSString *)imageURL withImage:(UIImage *)image;
    - (UIImage*) GetImage:(NSString *)imageURL;
    - (BOOL) DoesExist:(NSString *)imageURL;

    @end

ImageCache.m

  #import "ImageCache.h"

    @implementation ImageCache

    @synthesize imgCache;

    #pragma mark - Methods

    static ImageCache* sharedImageCache = nil;

    +(ImageCache*)sharedImageCache
    
        @synchronized([ImageCache class])
        
            if (!sharedImageCache)
                sharedImageCache= [[self alloc] init];

            return sharedImageCache;
        

        return nil;
    

    +(id)alloc
    
        @synchronized([ImageCache class])
        
            NSAssert(sharedImageCache == nil, @"Attempted to allocate a second instance of a singleton.");
            sharedImageCache = [super alloc];

            return sharedImageCache;
        

        return nil;
    

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

        return self;
    

   // - (void) AddImage:(NSString *)imageURL: (UIImage *)image
- (void) AddImage:(NSString *)imageURL withImage:(UIImage *)image
    
        [imgCache setObject:image forKey:imageURL];
    

    - (NSString*) GetImage:(NSString *)imageURL
    
        return [imgCache objectForKey:imageURL];
    

    - (BOOL) DoesExist:(NSString *)imageURL
    
        if ([imgCache objectForKey:imageURL] == nil)
        
            return false;
        

        return true;
    


    @end

示例

UIImage *image;

    // 1. Check the image cache to see if the image already exists. If so, then use it. If not, then download it.

    if ([[ImageCache sharedImageCache] DoesExist:imgUrl] == true)
    
        image = [[ImageCache sharedImageCache] GetImage:imgUrl];
    
    else
    
        NSData *imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: imgUrl]];
        image = [[UIImage alloc] initWithData:imageData];

        // Add the image to the cache 
        //[[ImageCache sharedImageCache] AddImage:imgUrl :image];

        [[ImageCache sharedImageCache] AddImage:imgUrl withImage:image];
    

【讨论】:

ImageCache.m 中的方法有一个错字:- (void) AddImage:(NSString *)imageURL: (NSString *)image 应该是- (void) AddImage:(NSString *)imageURL: (UIImage *)image(NSString *)image 应该是 (UIImage *)image 感谢您的出色回答。它充满了req。信息 非常有帮助的答案 +1,1 个问题这个缓存图像存储在哪里我检查了不包含它的文档目录,其他问题是这个代码如何删除这个缓存图像或不需要这样做? 干得好。但我建议 1. 为您的方法遵循 camelCase 命名约定; 2. 使用dispatch_once 实例化你的单例(参见Matt Galloway's singleton 讨论。 嗨,我和你在这里做的一样,但它不起作用。我想用 NSCache 在 customCell 中显示缩略图。这是我的帖子,***.com/questions/19252991/… 请看一下。谢谢..【参考方案2】:

在这里找到了一个很好的工作示例

http://ezekiel.vancouver.wsu.edu/~wayne/yellowjacket/YellowJacket.zip

【讨论】:

ios 5 的更新版本:git clone http://ezekiel.vancouver.wsu.edu/~cs458/demos/YellowJackets/.gitlink【参考方案3】:

您也可以尝试使用由enormego 的敏锐研究员编写的令人敬畏的 EgoImage 库来完成此操作。它使用非常简单,在后台有效利用缓存,非常适合满足您的要求。

这是包含演示应用程序的库的github path。

【讨论】:

【参考方案4】:

我为我一直在开发的一个应用程序编写了这个(概念和一些代码取自 Lane Roathe 的优秀 UIImageView+Cache 类别)。它也使用ASIHTTPRequest 类,这很棒。这绝对可以改进..例如,允许在不再需要时取消请求,或者通过使用通知 userInfo 来允许更精确的 UI 更新..但它对我的目的来说效果很好。

@implementation ImageFetcher
#define MAX_CACHED_IMAGES 20
static NSMutableDictionary* cache = nil;

+ (void)asyncImageFetch:(UIImage**)anImagePtr withURL:(NSURL*)aUrl 

    if(!cache) 
        cache = [[NSMutableDictionary dictionaryWithCapacity:MAX_CACHED_IMAGES] retain];
    

    UIImage* newImage = [cache objectForKey:aUrl.description];
    if(!newImage)  // cache miss - doh!
        ASIHTTPRequest *imageRequest = [ASIHTTPRequest requestWithURL:aUrl];    
        imageRequest.userInfo = [NSDictionary dictionaryWithObject:[NSValue valueWithPointer:anImagePtr] forKey:@"imagePtr"];
        imageRequest.delegate = self;
        [imageRequest setDidFinishSelector:@selector(didReceiveImage:)];
        [imageRequest setDidFailSelector:@selector(didNotReceiveImage:)];
        [imageRequest startAsynchronous];
    
    else  // cache hit - good!
        *anImagePtr = [newImage retain];    
    


+ (void)didReceiveImage:(ASIHTTPRequest *)request 
    NSLog(@"Image data received.");
    UIImage **anImagePtr = [(NSValue*)[request.userInfo objectForKey:@"imagePtr"] pointerValue];

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    UIImage *newImage = [[UIImage imageWithData:[request responseData]] retain];

    if(!newImage) 
        NSLog(@"UIImageView: LoadImage Failed");
    
    else 
        *anImagePtr = newImage;
        // check to see if we should flush existing cached items before adding this new item
        if( [cache count] >= MAX_CACHED_IMAGES)
            [cache removeAllObjects];

        [cache setValue:newImage forKey:[request url].description];

        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc postNotificationName: @"ImageDidLoad" object: self userInfo:request.userInfo];
    

    [pool drain];

你这样称呼这段代码:

[ImageFetcher asyncImageFetch:&icon withURL:url];

我也在使用通知,无论好坏,让相应 UIImage 的任何所有者知道他们应该何时重新显示 - 在这种情况下,它在 tableView 上下文中:

- (void)viewDidLoad 
    [super viewDidLoad];
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(imageDidLoad:) name:@"ImageDidLoad" object:nil];


- (void)imageDidLoad:(NSNotification*)notif 
    NSLog(@"Received icon load notification.");
    // reload table view so that new image appears.. would be better if I could
    // only reload the particular UIImageView that holds this image, oh well...
    [self.tableView reloadData];


- (void)dealloc 
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc removeObserver:self];
        // ...

【讨论】:

这里还有一个提示:如果您正在缓存大量图像或大图像,因此使用了大量内存,您可能需要创建一个“+ (void)flushCache” 方法执行“[cache removeAllObjects]”,因此您可以根据需要从 didReceiveMemoryWarning 方法中调用它。这将释放所有内存。【参考方案5】:

您可能还想查看HJCache。它带有一个 UIImageView 兼容的视图类,可以透明地完成所有缓存,适合在滚动性能很重要的 UITableViewCells 中使用。

【讨论】:

以上是关于缓存 URL 图片 iphone UITableview的主要内容,如果未能解决你的问题,请参考以下文章

iPhone SDK 远程文件存在,没有缓存

iphone URL Scheme 图片上传应用

Glide加载相同URL时由于缓存无法更新图片

iOS根据URL获得手机中的图片

缓存图片

iPhone - 从 URL 加载图像时内容不会滚动