IOS ленивая загрузка изображений таблиц

Я успешно реализовал ленивую загрузку изображений в моем приложении, используя пример, представленный apple здесь. Дело в том, что я хочу, чтобы изображение загружалось по мере прокрутки, но изображение загружается в ячейку только тогда, когда я заканчиваю перетаскивание (отпустите палец с экрана. До тех пор ячейка остается пустой). Я изменил код следующим образом:

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

    //NSLog(@"cell for row at indexpath, size - %f, current - %d", flowTable.contentSize.height, self.current);

    NSString *CellIdentifier = @"FlowCell";

    MyFlowCell *cell = (MyFlowCell *)[self.flowTable dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FlowCell" owner:nil options:nil];
       // cell = [nib objectAtIndex:0];

        for(id currentObject in nib)

        {

        if([currentObject isKindOfClass:[MyFlowCell class]])

        {
            cell = (MyFlowCell *)currentObject;

            break;
        }
        }
    }

    ImageDetails *rowItem = [self.imageData objectAtIndex:indexPath.row];

    if (!rowItem.mainImage)
    {  
       // if (self.flowTable.dragging == NO && self.flowTable.decelerating == NO)
       // {

            [self startIconDownload:rowItem forIndexPath:indexPath];

        //}

        cell.mainImage.backgroundColor = [UIColor grayColor];

    }
    else
    {

            cell.mainImage.image = rowItem.mainImage;

    }
    }


    return cell;
}


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
      //  [self loadImagesForOnscreenRows];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    //[self loadImagesForOnscreenRows];
}

Кроме того, я узнал, что в моем классе ImageDownloader NSURLConnection даже не получает ответ, пока я не отпущу свой палец с экрана. Я пытался выяснить, почему это происходит, но я пока не добился успеха. Скажите, пожалуйста, если я что-то упустил.

Ответ 1

Вы можете достичь ленивой загрузки в вашем табличном виде, выполнив следующие шаги:

В вашем классе Class.h поставьте:

NSMutableDictionary *Dict_name;
BOOL isDragging_msg, isDecliring_msg;

Теперь в файле Class.m, этот код в поле зрения загрузился:

Dict_name = [[NSMutableDictionary alloc] init];

В cellForRowAtIndexPath:

if ([dicImages_msg valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]]) { 
    cell.image_profile.image=[dicImages_msg valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]];
}
else
{
    if (!isDragging_msg && !isDecliring_msg)
    {
        [dicImages_msg setObject:[UIImage imageNamed:@"Placeholder.png"] forKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]];
        [self performSelectorInBackground:@selector(downloadImage_3:) withObject:indexPath];
    }
    else
    {
        cell.image_profile.image=[UIImage imageNamed:@"Placeholder.png"];
    }
}

И для загружаемого изображения функция:

-(void)downloadImage_3:(NSIndexPath *)path{
    NSAutoreleasePool *pl = [[NSAutoreleasePool alloc] init];

    NSString *str=[here Your image link for download];

    UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:str]]]; 

    [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"image name or image link same as cell for row"]];

    [tableview performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

    [pl release];
}

И, наконец, поставьте эти методы в свой класс:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    isDragging_msg = FALSE;     
    [tableview reloadData];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    isDecliring_msg = FALSE;
    [tableview reloadData]; 
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    isDragging_msg = TRUE;
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
    isDecliring_msg = TRUE; 
}

Ответ 2

Обновленный ответ:

Стандартный Apple LazyTableImages страдает несколькими недостатками:

  • Он не будет пытаться получить изображения до завершения прокрутки. Я понимаю, почему они решили это сделать (возможно, не хотят получать изображения, которые могут прокручиваться), но это приводит к тому, что изображения появляются медленнее, чем необходимо.

  • Он не ограничивает количество одновременных запросов некоторым разумным числом. Да, NSURLConnection будет автоматически замораживать запросы до тех пор, пока максимальное количество запросов не упадет до некоторого разумного числа, но в худшем случае у вас может быть время ожидания запросов, а не просто на очередность.

  • Как только он начнет загружать изображение, он не отменяет его, даже если ячейка впоследствии прокручивается с экрана.

Простым решением является удаление IconDownloader и всей логики прокрутки/замедления и просто использование категории UIImageView либо SDWebImage, либо AFNetworking.

Если вы собираетесь исправить это самостоятельно, потребуется немного усилий, чтобы все это было правильно. Но представляет собой выдачу LazyTableImages, которая использует NSOperationQueue, чтобы гарантировать (а) ограничение одновременных запросов; и (б) позволяет отменить запросы. Признаюсь, я предпочитаю вышеперечисленные реализации категорий UIImageView, лучше, но я попытался остаться со структурой оригинального Apple LazyTableImages, исправляя недостатки, перечисленные выше.

Ответ 3

Предполагая, что ваш UITableViewCell имеет свойство url и свойство UIImage для изображения (плюс свойство или статическое значение для очереди:

- (void) setThumbnailUrlString:(NSString *)urlString
{
    thumbnailUrlString = urlString;

    NSURL *url = [NSURL URLWithString:urlString];

    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    if ( queue == nil )
    {
        queue = [[NSOperationQueue alloc] init];
    }
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse * resp, NSData     *data, NSError *error) 
    {
        dispatch_async(dispatch_get_main_queue(),^ 
                       {
                            if ( error == nil && data )
                            {
                                UIImage *urlImage = [[UIImage alloc] initWithData:data];
                                thumbnail.image = urlImage;
                            }
                       });
    }];
}

Проблема с вашей реализацией заключается в том, что ваш метод загрузки изображений, вероятно, встречается в основном потоке. Вам необходимо загрузить изображение асинхронно, а затем обновить изображение в основном потоке.

Чтобы быть точным, блок должен проверить, соответствует ли URL-адрес ответа запрошенному URL-адресу, если изображение ячейки загружено слишком поздно, прежде чем ячейка будет повторно использована для другого изображения.

Ответ 5

Это довольно поздний ответ, но при изменении версии iOS подход продолжает меняться.

Чтобы лениво загружать изображения, рекомендуется рекомендуемый подход:

  • Загрузите URL-адреса всех изображений и сохраните их в своем контейнере (массив/объекты и т.д.).
  • Пожар a NSURLSessionTask (только пост iOS 7), который запускает async в фоновом режиме. Если вы находитесь под iOS 7, вы можете использовать NSURLConnection SendAsynchronousRequest API - он устарел в iOS 9, поэтому вам лучше избавиться от этого в ближайшее время.
  • Создайте свои изображения в фоновом режиме
  • Вернитесь в главную очередь, убедитесь, что у вас есть правильный UITableViewCell, а затем обновите изображение

Здесь - весь подход описан в моем учебнике.