Кэширование URL изображений iphone UITableview - PullRequest
11 голосов
/ 15 февраля 2010

Я ищу учебник о том, как кэшировать изображения, загруженные с URL, в ячейки uitableview.

Я нашел пример здесь

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

Но код неполный. Я объективный новичок, поэтому мне было очень трудно заполнить недостающие фрагменты.

Ответы [ 5 ]

35 голосов
/ 03 февраля 2012

Вот простая реализация ImageCache с использованием NSCache. 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];
    }
8 голосов
/ 15 февраля 2010

Хороший рабочий пример был найден здесь

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

2 голосов
/ 17 августа 2011

Вы также можете попробовать использовать потрясающую библиотеку EgoImage, написанную острыми парнями в enormego , чтобы выполнить это. Он очень прост в использовании, обеспечивает эффективное использование кэша за кулисами и идеально подходит для удовлетворения ваших требований.

Вот путь github для библиотеки, включающей демонстрационное приложение.

0 голосов
/ 06 декабря 2011

Вы также можете проверить HJCache . Он поставляется с классом представления, совместимым с UIImageView, который прозрачно выполняет все операции кэширования и подходит для использования в UITableViewCells, где важна производительность прокрутки.

0 голосов
/ 19 ноября 2010

Я написал это (с концепциями и некоторым кодом, взятым из превосходной категории UIImageView + Cache Лейна Роата) для приложения, над которым я работал. Он также использует классы ASIHTTPRequest , что отлично. Это определенно можно улучшить ... например, разрешив отменять запросы, если они больше не нужны, или используя уведомление userInfo для более точного обновления пользовательского интерфейса ... но это хорошо работает для моих целей.

@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];
        // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...