UITableView зарежда миниатюрни изображения асинхронно с кеша

Опитвам се да заредя миниатюрни изображения от отдалечен сайт в UITableView. Искам да направя това асинхронно и искам да внедря кеш на бедняк за миниатюрните изображения. Ето моя кодов фрагмент (ще опиша проблемното поведение по-долу):

@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];
    });
    
}

И така, ето проблемното поведение:

  1. Когато UITableView се зареди, миниатюрите не се показват в първоначалния набор от клетки. Едва когато клетка се премести извън екрана и след това се премести обратно, миниатюрата се показва.

  2. Кешът изобщо не работи. От това, което мога да кажа, не успява да запази миниатюрата в кеша. Тоест този ред е неуспешен:

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

  3. GCD опашката се създава/освобождава за всяка клетка. Освен това името на опашката е едно и също всеки път. Това лоша практика ли е?

Ще се радвам да посочите всичко, което видите, че е грешно, или дори коментари за общ подход. Благодаря.

Актуализация:

  1. РАЗРЕШЕНО: Добавих извикване за reloadRowsAtIndexPaths и сега миниатюрните изображения се зареждат в началните редове, които показват

  2. РАЗРЕШЕНО: Причината да се провали е, че добавяше обекта на изображението към речника, преди другата нишка да завърши настройването на този обект. Създадох метод на екземпляр за добавяне на обект към речника на свойствата, така че да мога да го извикам от вътрешността на блока, като гарантирам, че ще бъде добавен, след като обектът на изображението е зададен.


person Steven    schedule 14.04.2012    source източник
comment
Защо да го правите сами отново и отново, когато можете да използвате един помощник, за да направите всичко? Плащане на UIImageLoader. Това е супер просто, само два файла за добавяне към xcode. github.com/gngrwzrd/UIImageLoader   -  person gngrwzrd    schedule 25.12.2015
comment
Ако използвате swift и след това проверите AlamofireImage, това е страхотно. github.com/Alamofire/AlamofireImage   -  person neoneye    schedule 05.05.2016


Отговори (2)


1) Причината, поради която не се показва първоначално изображение, е, че клетката е изобразена с image = nil и така тя интелигентно скрива изгледа на изображението.

2) Опитахте ли да преместите тази линия във вашия блок?

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

3) Това е просто начин да разграничите опашките за отстраняване на грешки и да получите информация от конзолата, ако приложението ви се срине, можете да видите името на опашката. Това не би трябвало да е проблем, ако имате същото име за това, тъй като извършва същата операция. Не бихте искали да използвате това име в друг изглед на таблица, ако имате същата логика.

person Daniel    schedule 14.04.2012
comment
1) Благодаря. Добавих извикване за reloadRowsAtIndexPaths за този ред след зареждане на изображението и миниатюрата вече се появява при първоначално зареждане. 2) Не знам как да направя свойство, което може да се записва вътре в GCD блок. Как добавяте префикса __block при декларацията? - person Steven; 15.04.2012
comment
В крайна сметка създадох метод на екземпляр, който да добавя към речника на свойствата. По този начин мога да го извикам от вътрешността на блока. - person Steven; 15.04.2012

Определено трябва да погледнете SDWebImage. Това е точно това, което търсите. SDWebImage също е много бърз и може да използва многоядрени процесори.

person Jonas Schnelli    schedule 14.04.2012