我在 UICollectionView
中显示大量图像(5k 图像)。这些图像是从远程服务器下载的。当我从上到下滚动 UICollectionView
5 到 6 次时,我的应用程序崩溃,并收到错误“由于内存压力而终止应用程序”。请建议解决此问题。
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return urlLists.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
UIImageView *cellImage=[[UIImageView alloc]init];
cellImage.frame=cell.contentView.bounds;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[urlLists objectAtIndex:indexPath.row]]];
UIImage *image = [UIImage imageWithData:data];
UIImageJPEGRepresentation(image, 0.1);
data=nil;
dispatch_async(dispatch_get_main_queue(), ^{
cellImage.image=image;
});
});
NSLog(@"The Indexpath=%ld", indexPath.row);
[cell.contentView addSubview:cellImage];
return cell;
}
最佳答案
这里存在三个级别的问题:
最严重的问题是每次使用单元格时都会向该单元格添加一个新的
UIImageView
。但单元格可以重复使用多次,因此您要向单元格添加许多 ImageView 。与所有其他 ImageView 关联的图像将占用内存。我认为最简单/最好的解决方案是使用单元原型(prototype),在其中添加 ImageView ,并且不要以编程方式添加 ImageView 。或者,您可以通过编程方式添加 ImageView ,但请确保不要每次都添加新的 ImageView 。
顺便说一句,不要试图通过每次手动实例化一个新单元来关闭单元重用(正如其他人可能建议的那样)。是的,这是一个简单的解决方案,但不是一个有效的解决方案。
一个更微妙的问题是,您调用
UIImageJPEGRepresentation
我猜测是为了减少所涉及的内存。这并不像你想象的那样。是的,它会创建一个压缩的 JPEG 表示形式,但您无需对其执行任何操作。你只是将其丢弃。如果您想优化内存并且图像具有高分辨率,请考虑将图像大小调整为适合单元格的大小。请参阅UIImage resizing not working properly例如调整类别大小。
考虑使用 SDWebImage 的
UIImageView
类别或AFNetworking ,它会延迟加载和缓存图像。问题中的这段代码在启动异步检索之前不会正确重置 ImageView 。如果在图像检索完成之前重复使用单元格,它将无法处理这种情况。它可能会不必要地重新检索几秒钟前下载的图像。等等
与优雅地异步检索图像相关的问题有很多,而这两个类的
UIImageView
类别会为您处理很多这些细节。
关于ios - 滚动从远程服务器加载大量图像的 UICollectionView 时如何避免内存问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30374373/