UICollectionView - загрузка изображений и эффективная перезагрузка данных, таких как Instagram
Я заметил, что приложения, такие как Intagram, используют UICollectionViews
для отображения фида фотографий.
Я также заметил, что ячейки для этих фотографий каким-то образом размещены на экране до, фактические фотографии загружаются полностью. Затем, когда загрузка завершается, эта фотография хорошо отображается в правильной ячейке.
Я хотел бы скопировать эту функциональность, но я не знаю, как это сделать.
В настоящее время я загружаю большой объект JSON, который я преобразовываю в массив NSdictionaries. Каждый NSDictionary
содержит информацию о каждой фотографии, и среди этой информации представлен URL-адрес. На этом URL-адресе я могу найти соответствующее изображение, которое мне нужно загрузить и отобразить в моем UICollectionViewCells
Как и сейчас, я повторяю этот список и запускаю загрузку для каждого URL, который я вижу. Когда эта загрузка будет завершена, я перезагружу коллекцию с помощью [self.collectionView reloadData]
. Но, как вы можете себе представить, если у меня есть 30 ячеек, которые все хотят изображения, существует много вызовов reloadData
.
Я использую AFNetworking для обработки загрузки, вот метод, который я вызываю на основе URL, о котором я упоминал ранее:
-(void) downloadFeedImages:(NSString *) photoURL imageDescs:(NSDictionary*)imageDescs photoId:(NSString *)photoID{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
NSString* foofile = [directory stringByAppendingPathComponent:photoID];
if([[NSFileManager defaultManager] fileExistsAtPath:foofile]){
// IF IMAGE IS CACHED
[self.collectionView reloadData];
return;
}
NSLog(@"photoURL: %@", photoURL);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:photoURL]];
AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
// Save Image
NSLog(@"URL-RESPONSE:%@", image);
NSString *myFile = [directory stringByAppendingPathComponent:photoID];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:myFile atomically: YES];
[self.collectionView reloadData];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"ERROR: %@", [error localizedDescription]);
}];
[[WebAPI sharedInstance] enqueueHTTPRequestOperation:operation];
}
Итак,, мне интересно, как я могу добиться того, что Instagram и подобные приложения имеют дело с отображением фида с изображениями.
Кроме того, я хотел бы знать хороший способ инициировать загрузку для каждой ячейки, и когда эта загрузка будет завершена, обновите эту ячейку, а не перерисуйте весь вид, используя [reloadData]
Спасибо
Ответы
Ответ 1
Техника, которую вы хотите реализовать, называется ленивой загрузкой. Поскольку вы используете AFNetworking
, это будет проще реализовать в вашем случае. Каждой ячейке просмотра коллекции требуется UIImageView
для отображения изображения. Используйте категорию UIImageView+AFNetworking.h
и установите правильный URL изображения, вызывая метод
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// ....
[cell.imageView setImageWithURL:imageURL placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
// ...
return cell;
}
Заполнитель - это изображение, которое будет отображаться до загрузки необходимого изображения. Это просто сделает вам необходимую работу.
Примечание. По умолчанию URL-запросы имеют политику кэширования NSURLCacheStorageAllowed
и интервал тайм-аута 30 секунд, и они не обрабатывают файлы cookie. Чтобы настроить URL-адреса по-разному, используйте setImageWithURLRequest:placeholderImage:success:failure:
.
Кроме того, для справки, если вы хотите реализовать ленивую загрузку изображений самостоятельно, следуйте этому образцу кода Apple. Это для UITableView
, но тот же метод можно использовать и для UICollectionView
.
Надеюсь, что это поможет!
Ответ 2
использование
[self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
вместо
[self.collectionView reloadData];
здесь indexPath
- это объект NSIndexPath
для соответствующего объекта UICollectionViewCell
Object
Ответ 3
Использовать следующее для загрузки изображения Async в ячейке в cellForItemAtIndexPath метод делегата
let url = URL(string: productModel.productImage)
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async(execute: {
collectionViewCell.imageView.image = UIImage(data: data!)
});
Использовать протокол "UICollectionViewDataSourcePrefetching" в вашем ViewController как
класс ViewController: UIViewController, UICollectionViewDataSourcePrefetching {
Установите следующие делегаты в виде коллекции в раскадровке (см. прикрепленное изображение)
или программно
В режиме ViewController ViewDidLoad
collectionView.delegate = self
collectionView.dataSource = self
collectionView.prefetchDataSource = self