11

URLから読み込まれた画像をuitableviewのセルにキャッシュする方法に関するチュートリアルを探しています。

ここで例を見つけました

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

しかし、コードは不完全です。私は客観的な初心者なので、欠けている部分を埋めるのは非常に難しいと感じました。

4

5 に答える 5

35

これは、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];
    }
于 2012-02-03T18:17:34.403 に答える
8

素敵な実例がここに見つかりました

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

于 2010-02-15T11:39:21.693 に答える
2

これを達成するために、 enormegoの鋭い仲間によって書かれた素晴らしい EgoImage ライブラリを使用することもできます。使い方は非常に簡単で、バックグラウンドでキャッシュを効率的に使用できるため、要件を満たすのに最適です。

デモ アプリを含むライブラリのgithub パスは次のとおりです。

于 2011-08-17T06:56:25.017 に答える
0

また、 HJCacheを確認することもできます。すべてのキャッシュを透過的に実行するUIImageView互換のビュークラスが付属しており、スクロールパフォーマンスが重要なUITableViewCellsでの使用に適しています。

于 2011-12-06T10:31:50.567 に答える
0

これは、私が取り組んでいるアプリのために (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];
        // ...
}
于 2010-11-19T16:02:30.430 に答える