ios – UICollection使用SDWebImage查看滚动延迟

ios – UICollection使用SDWebImage查看滚动延迟,第1张

概述背景 我搜索了SO和苹果论坛.相当多的人谈到了带图像的集合视图单元的性能.他们中的大多数人表示,由于在主线程中加载图像,因此滚动滞后. 通过使用SDWebImage,图像应该在单独的线程中加载.但是,它仅在iPad模拟器中的横向模式下滞后. 问题描述 在纵向模式下,集合视图为每行加载3个单元格.它没有滞后或微不足道的延迟. 在横向模式下,集合视图为每行加载4个单元格.并且它具有明显的滞后和帧速率下 背景

我搜索了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查看滚动延迟所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1086248.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-27
下一篇2022-05-27

发表评论

登录后才能评论

评论列表(0条)

    保存