Ios UICollectionView-下载图像并有效地重新加载数据,如Instagram
我注意到像Intagram这样的应用程序使用Ios UICollectionView-下载图像并有效地重新加载数据,如Instagram,ios,objective-c,cocoa-touch,afnetworking,uicollectionview,Ios,Objective C,Cocoa Touch,Afnetworking,Uicollectionview,我注意到像Intagram这样的应用程序使用UICollectionViews来显示照片提要。 我还注意到,在实际照片完全下载之前,这些照片的单元格以某种方式被放置在屏幕上。然后,当下载完成时,该照片会很好地显示在正确的单元格中 我想复制这个功能,但我不知道该怎么做 我目前正在下载一个大型的JSON对象,我将其转换为一组NSDictionary。每个NSDictionary都包含关于每张照片的信息,在这些信息中,会显示一个URL。在这个URL上,我可以找到需要下载并显示在我的UICollecti
UICollectionViews
来显示照片提要。
我还注意到,在实际照片完全下载之前,这些照片的单元格以某种方式被放置在屏幕上。然后,当下载完成时,该照片会很好地显示在正确的单元格中
我想复制这个功能,但我不知道该怎么做
我目前正在下载一个大型的JSON对象,我将其转换为一组NSDictionary。每个NSDictionary
都包含关于每张照片的信息,在这些信息中,会显示一个URL。在这个URL上,我可以找到需要下载并显示在我的UICollectionViewCells
现在,我迭代这个列表,并为我看到的每个URL启动下载。下载完成后,我使用[self.collectionview reloadData]
重新加载collectionview。但是,正如你所能想象的,如果我有30个细胞都想要一个图像,就会有大量的重新加载数据
调用
我正在使用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]
谢谢您想要实现的技术称为延迟加载。由于您使用的是
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秒,并且设置为不处理cookies。要以不同方式配置URL请求,请使用setImageWithURLRequest:Placeholder图像:成功:失败:
另外,为了便于参考,如果您想自己实现图像的延迟加载,请遵循以下步骤。这适用于UITableView
,但同样的技术也可用于UICollectionView
希望有帮助 使用
[self.collectionView reloadeitemsatindexpaths:[NSArray arrayWithObject:indexPath]]代码>
而不是
[self.collectionView-reloadData]代码>
这里,indepath
是对应的UICollectionViewCell
对象的nsindepath
对象使用以下方法在CellForItemIndexPath委托方法的单元格中异步加载图像
let url = URL(string: productModel.productImage)
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async(execute: {
collectionViewCell.imageView.image = UIImage(data: data!)
});
在ViewController中实现协议“UICollectionViewDataSourcePrefetching”,如下所示:
类ViewController:UIViewController,UICollectionViewDataSourcePrefetching{
在序列图像板中将以下代理设置为集合视图(请参见附图)
或以编程方式
在ViewController的viewDidLoad方法中
然而,当我实现这一点时,collectionview在滚动时非常有问题。这个方法完全异步吗?你知道如何使我的collectionview滚动不那么有问题吗?=)@Eyball是的,这是完全异步的。你在cellForItemAtIndexPath
中执行的其他操作是否与FileIO类似?有操作吗可能导致主线程中出现明显停顿的设置?还有一件事,您现在不需要重新加载每个图像的集合。下载并分配图像后,AFNetworking代码将负责刷新图像视图。您可以使用相同的分类功能,该功能将首先在AFNetworking缓存中查找,如果找到,将使用se本地副本,如果没有,它将下载新副本。如果设备收到内存不足警告,则你的应用缓存目录将被删除,要求你重新下载并管理缓存。相反,让AFNetworking高效地执行此操作:)此外,AFNetworking将在缓存时处理资源刷新,例如它将检查Etag中的缓存图像。如果ovider在同一url处更改图像资源,然后AFNetworking将下载修改后的资源并替换为缓存的url。否UICollectionViewDataSourcePrefetching
仅在iOS 10上有效+
collectionView.delegate = self
collectionView.dataSource = self
collectionView.prefetchDataSource = self