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: изображение для ключа: 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) Причина, по которой исходное изображение не отображается, заключается в том, что ячейка визуализируется с изображением = 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