Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView loading thumbnail images asynchronously with cache

I'm trying to load thumbnail images from a remote site onto a UITableView. I want to do this asynchronously, and I want to implement a poorman's cache for the thumbnail images. Here's my code snippet (I'll describe the problematic behavior below):

@property (nonatomic, strong) NSMutableDictionary *thumbnailsCache;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

// ...after obtaining the cell:

NSString *thumbnailCacheKey = [NSString stringWithFormat:@"cache%d", indexPath.row];

if (![[self.thumbnailsCache allKeys] containsObject:thumbnailCacheKey]) {
    
    // thumbnail for this row is not found in cache, so get it from remote website
    __block NSData *image = nil;        
    dispatch_queue_t imageQueue = dispatch_queue_create("queueForCellImage", NULL);
    dispatch_async(imageQueue, ^{
        NSString *thumbnailURL = myCustomFunctionGetThumbnailURL:indexPath.row;
        image = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:thumbnailURL]];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.imageView.image = [UIImage imageWithData:image];
        });
    });
    dispatch_release(imageQueue);
    [self.thumbnailsCache setObject:image forKey:thumbnailCacheKey];
    
} else {
    
    // thumbnail is in cache
    NSData *image = [self.thumbnailsCache objectForKey:thumbnailCacheKey];
    dispatch_async(dispatch_get_main_queue(), ^{
        cell.imageView.image = [UIImage imageWithData:image];
    });
    
}

So here are the problematic behaviors:

  1. When the UITableView loads, thumbnails don't show up on the initial set of cells. Only when a cell moves off screen then moves back on does the thumbnail show up.

  2. Cache isn't working at all. From what I can tell, it fails to save the thumbnail to cache altogether. That is, this line fails:

    [self.thumbnailsCache setObject:image forKey:thumbnailCacheKey];

  3. The GCD queue is getting created/released for each cell. Furthermore, the queue name is the same every time. Is this bad practice?

I'd appreciate you guys pointing out anything you see that is wrong, or even any general approach comments. Thanks.

Update:

  1. RESOLVED: I added a call to reloadRowsAtIndexPaths and now the thumbnail images load on initial rows that display

  2. RESOLVED: The reason it was failing is because it was adding the image object to the dictionary before the other thread completed setting that object. I created an instance method to add object to the property dictionary, so that I can call it from inside the block, ensuring it gets added after the image object is set.

like image 567
Steven Avatar asked Oct 08 '22 02:10

Steven


1 Answers

You should definitively take a look at SDWebImage. It's exactly what your looking for. SDWebImage is also very fast and can use multicore CPU's.

like image 100
Jonas Schnelli Avatar answered Oct 12 '22 11:10

Jonas Schnelli