
我搜索了SO和苹果论坛.相当多的人谈到了带图像的集合视图单元的性能.他们中的大多数人表示,由于在主线程中加载图像,因此滚动滞后.
通过使用SDWebImage,图像应该在单独的线程中加载.但是,它仅在iPad模拟器中的横向模式下滞后.
问题描述
在纵向模式下,集合视图为每行加载3个单元格.它没有滞后或微不足道的延迟.
在横向模式下,集合视图为每行加载4个单元格.并且它具有明显的滞后和帧速率下降.
我用仪器工具检查了核心动画.当出现新单元格时,帧速率降至约8fps.我不确定哪种行为会给集合视图带来如此低的性能.
希望有人知道这些技巧.
这是关联代码
在视图控制器中
- (UICollectionVIEwCell *)collectionVIEw:(UICollectionVIEw *)collectionVIEw cellForItemAtIndexPath:(NSIndexPath *)indexPath{ ProductCollectionVIEwCell *cell=[collectionVIEw dequeueReusableCellWithReuseIDentifIEr:@"ProductVIEwCell" forIndexPath:indexPath]; Product *tmpProduct = (Product*)_ploader.loadedProduct[indexPath.row]; cell.product = tmpProduct; if (cellShouldAnimate) { cell.Alpha = 0.0; [UIVIEw animateWithDuration:0.2 delay:0 options:(UIVIEwAnimationoptionCurvelinear | UIVIEwAnimationoptionAllowUserInteraction) animations:^{ cell.Alpha = 1.0; } completion:nil]; } if(indexPath.row >= _ploader.loadedProduct.count - ceil((liMIT_COUNT * 0.3))) { [_ploader loadProductsWithCompleteBlock:^(NSError *error){ if (nil == error) { cellShouldAnimate = NO; [_collectionVIEw reloadData]; dispatch_after(dispatch_time(disPATCH_TIME_Now,2 * NSEC_PER_SEC),dispatch_get_main_queue(),^{ cellShouldAnimate = YES; }); } else if (error.code != 1){ #ifdef DEBUG_MODE ulog(@"Error.des : %@",error.description); #else CustomAlertVIEw *alertVIEw = [[CustomAlertVIEw alloc] initWithTitle:@"Connection Error" message:@"Please retry." buttonTitles:@[@"OK"]]; [alertVIEw show]; #endif } }]; } return cell;} 在collectionVIEwCell中准备ForReuse
- (voID)prepareForReuse{ [super prepareForReuse]; CGRect bounds = self.bounds; [_thumbnailimgVIEw sd_cancelCurrentimageLoad]; CGfloat labelsTotalHeight = bounds.size.height - _thumbnailimgVIEw.frame.size.height; CGfloat brandToImageOffset = 2.0; if (UI_USER_INTERFACE_IdioM() == UIUserInterfaceIdiomPad) { brandToImageOffset = 53.0; } CGfloat labelStartY = _thumbnailimgVIEw.frame.size.height + _thumbnailimgVIEw.frame.origin.y + brandToImageOffset; CGfloat nameLblHeight = labelsTotalHeight * 0.46; CGfloat priceLblHeight = labelsTotalHeight * 0.18; _brandLbl.frame = (CGRect){{15,labelStartY},{bounds.size.wIDth - 30,nameLblHeight}}; CGfloat pricetonameOffset = 8.0; if (UI_USER_INTERFACE_IdioM() == UIUserInterfaceIdiomPad) { pricetonameOffset = 18.0; } _priceLbl.frame = (CGRect){{5,labelStartY + nameLblHeight - pricetonameOffset},{bounds.size.wIDth-10,priceLblHeight}}; [_spinner stopAnimating]; [_spinner removeFromSupervIEw]; _spinner = nil;} 覆盖setProduct方法
- (voID)setProduct:(Product *)product{ _product = product; _spinner = [[UIActivityIndicatorVIEw alloc] initWithActivityIndicatorStyle:UIActivityIndicatorVIEwStyleGray]; _spinner.center = CGPointMake(CGRectGetMIDX(self.bounds),CGRectGetMIDY(self.bounds)); [self addSubvIEw:_spinner]; [_spinner startAnimating]; _spinner.hIDesWhenStopped = YES; // Add a spinner __block UIActivityIndicatorVIEw *tmpSpinner = _spinner; __block UIImageVIEw *tmpimgVIEw = _thumbnailimgVIEw; Productimage *thumbnailImage = _product.images[0]; [_thumbnailimgVIEw sd_setimageWithURL:[NSURL URLWithString:thumbnailImage.mediumURL] completed:^(UIImage *image,NSError *error,SDImageCacheType cacheType,NSURL *imageURL) { // dismiss the spinner [tmpSpinner stopAnimating]; [tmpSpinner removeFromSupervIEw]; tmpSpinner = nil; if (nil == error) { // Resize the incoming images dispatch_async(dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_DEFAulT,0),^{ CGfloat imageHeight = image.size.height; CGfloat imageWIDth = image.size.wIDth; CGSize newSize = tmpimgVIEw.bounds.size; CGfloat scaleFactor = newSize.wIDth / imageWIDth; newSize.height = imageHeight * scaleFactor; UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0); [image drawInRect:CGRectMake(0,newSize.wIDth,newSize.height)]; UIImage *small = UIGraphicsGetimageFromCurrentimageContext(); UIGraphicsEndImageContext(); dispatch_async(dispatch_get_main_queue(),^{ tmpimgVIEw.image = small; }); }); if (cacheType == SDImageCacheTypeNone) { tmpimgVIEw.Alpha = 0.0; [UIVIEw animateWithDuration:0.2 delay:0 options:(UIVIEwAnimationoptionCurvelinear | UIVIEwAnimationoptionAllowUserInteraction) animations:^{ tmpimgVIEw.Alpha = 1.0; } completion:nil]; } } else { // loading error [tmpimgVIEw setimage:[UIImage imagenamed:@"broken_image_small"]]; } }]; _brandLbl.text = [_product.brand.name uppercaseString]; _nameLbl.text = _product.name; [_nameLbl sizetoFit]; // Format the price NSNumberFormatter * floatFormatter = [[NSNumberFormatter alloc] init]; [floatFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; [floatFormatter setDecimalSeparator:@"."]; [floatFormatter setMaximumFractionDigits:2]; [floatFormatter setMinimumFractionDigits:0]; [floatFormatter setGrouPingSeparator:@","]; _priceLbl.text = [Nsstring stringWithFormat:@"$%@ USD",[floatFormatter stringFromNumber:_product.price]]; if (_product.salePrice.intValue > 0) { Nsstring *rawStr = [Nsstring stringWithFormat:@"$%@ $%@ USD",[floatFormatter stringFromNumber:_product.price],[floatFormatter stringFromNumber:_product.salePrice]]; NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:rawStr]; // Change all the text to red first [string addAttribute:NSForegroundcolorAttributename value:[UIcolor colorWithRed:157/255.0 green:38/255.0 blue:29/255.0 Alpha:1.0] range:NSMakeRange(0,rawStr.length)]; // find the first space NSRange firstSpace = [rawStr rangeOfString:@" "]; // Change from zero to space to gray color [string addAttribute:NSForegroundcolorAttributename value:_priceLbl.textcolor range:NSMakeRange(0,firstSpace.location)]; [string addAttribute:NsstrikethroughStyleAttributename value:@2 range:NSMakeRange(0,firstSpace.location)]; _priceLbl.attributedText = string; }}解决方法 SDWebImage非常令人钦佩,但DlimageLoader绝对令人难以置信,是许多大型制作应用程序的关键部分 https://stackoverflow.com/a/19115912/294884
它非常容易使用.
为了避免撇脂问题,基本上只是在开始下载图像之前引入延迟.所以,基本上就像这样…就是这么简单
dispatch_after_secs_on_main(0.4,^ { if ( ! [urlWasThen isEqualToString:self.currentimage] ) { // so in other words,in fact,after a short period of time,// the user has indeed scrolled away from that item. // (IE,the user is skimming) // this item is Now some "new" item so of course we don't // bother loading "that old" item // IE,we Now kNow the user was simply skimming over that item. // (just TBC in the preliminary clause above,// since the image is already in cache,// we'd just instantly load the image - even if the user is skimming) // NSLog(@" --- --- --- --- --- --- too quick!"); return; } // a short time has passed,and indeed this cell is still "that" item // the user is NOT skimming,SO we start loading the image. //NSLog(@" --- not too quick "); [DlimageLoader loadImageFromURL:urlWasThen completed:^(NSError *error,NSData *imgData) { if (self == nil) return; // some time has passed while the image was loading from the internet... if ( ! [urlWasThen isEqualToString:self.currentimage] ) { // note that this is the "normal" situation where the user has // moved on from the image,so no need toload. // // in other words: in this case,not due to skimming,// but because SO much time has passed,// the user has moved on to some other part of the table. // we pointlessly loaded the image from the internet! doh! //NSLog(@" === === 'too late!' image load!"); return; } UIImage *image = [UIImage imageWithData:imgData]; self.someImage.image = image; }]; }); 这是“非常容易”的解决方案.
IMO经过大量的实验后,实际上比滚动浏览时更复杂的跟踪解决方案更好.
再一次,DlimageLoader让这一切变得非常简单https://stackoverflow.com/a/19115912/294884
请注意,上面的代码部分只是在单元格中加载图像的“常规”方式.
这是典型的代码,可以做到这一点:
-(voID)imageIsNow:(Nsstring *)imUrl { // call this routine o "set the image" on this cell. // note that "image is Now" is a better name than "set the image" // Don't forget that cells very rAPIdly change contents,due to // the cell reuse paradigm on iOS. // this cell is being told that,the image to be displayed is Now this image // being aware of scrolling/skimming issues,cache issues,etc,// utilise this information to apprporiately load/whatever the image. self.someImage.image = nil; // that's UIImageVIEw self.currentimage = imUrl; // you need that string property [self loadImageInASecIfItsTheSameAs:imUrl]; }-(voID)loadImageInASecIfItsTheSameAs:(Nsstring *)urlWasThen { // (note - at this point here the image may already be available // in cache. if so,just display it. I have omitted that // code for simplicity here.) // so,right here,"possibly load with delay" the image // exactly as shown in the code above ..... dispatch_after_secs_on_main(0.4,^ ...etc.... ...etc.... } 由于DlimageLoader非常棒,所以这一切都很容易实现.这是一个非常坚固的图书馆.
总结以上是内存溢出为你收集整理的ios – UICollection使用SDWebImage查看滚动延迟全部内容,希望文章能够帮你解决ios – UICollection使用SDWebImage查看滚动延迟所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)