Ios UICollectionView使用AFNetworking加载图像的滚动性能
我读过不少UICollectionView关于糟糕滚动的帖子,但似乎没有一篇直接适用,或者它们仍然没有得到回答 我使用Ios UICollectionView使用AFNetworking加载图像的滚动性能,ios,objective-c,scroll,afnetworking,uicollectionview,Ios,Objective C,Scroll,Afnetworking,Uicollectionview,我读过不少UICollectionView关于糟糕滚动的帖子,但似乎没有一篇直接适用,或者它们仍然没有得到回答 我使用AFNetworking将图像(95px平方)异步加载到每个单元格中,然后当图像再次滚动到视图中时,图像从缓存中恢复(由响应代码0而不是200验证) 以下是我尝试过的: 注释掉weakCell.photoView.image=image这样图像就不会在屏幕上绘制,滚动也更平滑(在HTTP get过程中仍然有点结巴) 从cellforrowatinedxpath方法中删除了所有A
AFNetworking
将图像(95px平方)异步加载到每个单元格中,然后当图像再次滚动到视图中时,图像从缓存中恢复(由响应代码0而不是200验证)
以下是我尝试过的:
- 注释掉
weakCell.photoView.image=image代码>这样图像就不会在屏幕上绘制,滚动也更平滑(在HTTP get过程中仍然有点结巴)
- 从
方法中删除了所有AFNetworking代码,滚动更加平滑(即使自定义单元格阴影等仍在屏幕上绘制)cellforrowatinedxpath
- 当我在屏幕上只绘制单元视图(带阴影)时,100个单元的滚动非常平滑。当我开始在屏幕上绘制图像时,我的设备上的滚动效果很差,甚至在模拟器上也很明显。Instagram在他们的个人资料视图上有数百个单元格,滚动非常平滑,所以我试图接近他们的性能李>
#import "PhotoGalleryCell.h"
@implementation PhotoGalleryCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Setup the background color, shadow, and border
self.backgroundColor = [UIColor colorWithWhite:0.25f alpha:1.0f];
self.layer.borderColor = [UIColor blackColor].CGColor;
self.layer.borderWidth = 0.5f;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowRadius = 3.0f;
self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f);
self.layer.shadowOpacity = 0.5f;
// Make sure we rasterize for retina
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
self.layer.shouldRasterize = YES;
// Add to the content view
self.photoView = [[UIImageView alloc] initWithFrame:self.bounds];
[self.contentView addSubview:self.photoView];
}
return self;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.photoView.image = nil;
self.largeImageURL = nil;
}
这是我的UICollectionView代码:
#pragma mark - Collection View Delegates
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [zePhotos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoGalleryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPGPhotoCellIdentifier forIndexPath:indexPath];
// Get a reference to the image dictionary
NSDictionary *photoDict = [[zePhotos objectAtIndex:indexPath.row] objectForKey:@"image"];
// Asynchronously set the thumbnail view
__weak PhotoGalleryCell *weakCell = cell;
NSString *thumbnailURL = [[photoDict objectForKey:@"thumbnail"] objectForKey:@"url"];
NSURLRequest *photoRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:thumbnailURL]];
[cell.photoView setImageWithURLRequest:photoRequest
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.photoView.image = image;
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"Error retrieving thumbnail... %@", [error localizedDescription]);
}];
// Cache the large image URL in case they tap on this cell later
cell.largeImageURL = [[photoDict objectForKey:@"large"] objectForKey:@"url"];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:@"showPhotoDetail" sender:self];
}
代码检查看起来不错,尽管我打赌是阴影的合成增加了很多延迟。要准确找出造成延迟的原因,可以在仪器中使用时间分析器工具 问题是,当您快速滚动时,您同时启动了数百个网络请求。如果缓存了图像,请立即显示它。如果没有,请仅在表视图速度减慢时开始下载 您可以使用以下内容:
//Properties or Instance Variables
NSDate *scrollDateBuffer;
CGPoint scrollOffsetBuffer;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSTimeInterval secondsSinceLastScroll = [[NSDate date] timeIntervalSinceDate:scrollDateBuffer];
CGFloat distanceSinceLastScroll = fabsf(scrollView.contentOffset.y - scrollOffsetBuffer.y);
BOOL slow = (secondsSinceLastScroll > 0 && secondsSinceLastScroll < 0.02);
BOOL small = (distanceSinceLastScroll > 0 && distanceSinceLastScroll < 1);
if (slow && small) {
[self loadImagesForOnscreenRows];
}
scrollDateBuffer = [NSDate date];
scrollOffsetBuffer = scrollView.contentOffset;
}
我把它放在try/catch块中,因为根据我的经验,[UITableView-visibleCells]
不可靠-它偶尔会返回释放的单元格或没有superview的单元格。如果您确保仅在表没有快速滚动时调用此方法,则不会对滚动性能产生太大影响
另外,请注意,AFUIImageView类别不公开缓存对象。您需要稍微修改它,以检查是否已经缓存了图像;应该会为您指明正确的方向。您可以尝试向cell init添加阴影路径,这会提高性能,这就是我在一个项目中添加圆形阴影路径的代码(有关更多选择,请参阅UIBezierPath方法) 此外,如果我没记错,AFNetworking不会调整从服务器返回的图像的大小,因此可能会影响图像的质量(尽管您在UIImageView中添加了缩放方法),如果您愿意,我建议调度返回的图像以调整其大小:
CGSize targetSize = cell.photoView.bounds.size;
[cell.photoView setImageWithURLRequest:photoRequest
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGFloat imageHeight = image.size.height;
CGFloat imageWidth = image.size.width;
CGSize newSize = weakCell.imageView.bounds.size;
CGFloat scaleFactor = targetSize.width / imageWidth;
newSize.height = imageHeight * scaleFactor;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *small = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(),^{
weakCell.photoView.image = small;
});
});
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"Error retrieving thumbnail... %@", [error localizedDescription]);
}];
当我在屏幕上只绘制单元视图(带阴影)时,100个单元的滚动非常平滑。当我开始在屏幕上绘制图像时,我的设备上的滚动效果很差,甚至在模拟器上也很明显。Instagram在他们的个人资料视图中可以平滑地滚动数百个单元格,因此我试图接近他们的性能。请注意,我的答案包括有关UITableView的信息,而您使用的是UICollectionView。同样的答案也适用,因为UICollectionView遵循相同的设计模式。很抱歉响应太晚!AFNetworking应该已经针对UIScrollView的任何子类(如您列出的子类)进行了优化,因此应该已经注意到这一点。您是否成功地解决了此问题?“我正在做同样的事情,如果你有后续行动,我将非常感激。”@Tres抱歉,但我现在不得不接受这次表演。AFNetworking表示它已经针对UIScrollView的任何子类(如UITableView或UICollectionView)进行了优化,但这似乎是UI性能差的原因。谢谢您的回答。正如我在OP中所说:当我只在屏幕上绘制单元格视图(带阴影)时,100个单元格的滚动非常平滑。当我开始在屏幕上绘制图像时,我的设备上的滚动效果很差,甚至在模拟器上也很明显。因此,这似乎是网络图像缓存的一个问题。
self.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.frame.bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(10, 10)].CGPath;
CGSize targetSize = cell.photoView.bounds.size;
[cell.photoView setImageWithURLRequest:photoRequest
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGFloat imageHeight = image.size.height;
CGFloat imageWidth = image.size.width;
CGSize newSize = weakCell.imageView.bounds.size;
CGFloat scaleFactor = targetSize.width / imageWidth;
newSize.height = imageHeight * scaleFactor;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *small = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(),^{
weakCell.photoView.image = small;
});
});
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"Error retrieving thumbnail... %@", [error localizedDescription]);
}];