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-адресу, если изображение ячейки загружено слишком поздно, прежде чем ячейка будет повторно использована для другого изображения.
Ответ 4
Я сделал эту структуру, которая содержит ленивый контроллер нагрузки. Он прост в использовании и работает из коробки.
https://github.com/cloverstudio/CSUtils
Учебное пособие можно найти здесь:
http://www.clover-studio.com/blog/using-csutils-ios-framework-for-lazy-loading-images/
Ответ 5
Это довольно поздний ответ, но при изменении версии iOS подход продолжает меняться.
Чтобы лениво загружать изображения, рекомендуется рекомендуемый подход:
- Загрузите URL-адреса всех изображений и сохраните их в своем контейнере (массив/объекты и т.д.).
- Пожар a NSURLSessionTask (только пост iOS 7), который запускает async в фоновом режиме. Если вы находитесь под iOS 7, вы можете использовать NSURLConnection SendAsynchronousRequest API - он устарел в iOS 9, поэтому вам лучше избавиться от этого в ближайшее время.
- Создайте свои изображения в фоновом режиме
- Вернитесь в главную очередь, убедитесь, что у вас есть правильный UITableViewCell, а затем обновите изображение
Здесь - весь подход описан в моем учебнике.