Instruments Time profiler 调优APP 之图片解码

  • 以前闲时用instruments的Time profiler调试过APP,发现用tableView: cellForRowAtIndexPath: 中cell的图片设置耗时较多,之前改了一下,如下
dispatch_async(dispatch_get_global_queue(0, 0), ^{
        UIImage *cellImage = [UIImage imageNamed: self.imageNamesArray[indexPath.row] ];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.imageView.image = cellImage;
        });
    });

    发现没什么效果,就没去改了(这就是不求甚解,😂),直到最近被人问到图片的显示流程,去网上搜索相关资料,才发现用imageNamed的这种方式创建的图片,并不会立即解码,而是发生在CALayerPrepareCommit后 提交到GPU之前,才会去解码,那样总是会在主线程解码的,参考图片网址,参考YYKit大神写的文章

 

   后来在GitHub上面搜到了一种解决方案,就是在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap中直接创建图片,UIImage+ImmediateDecode.m中主要代码如下

+ (instancetype)imageWithName:(NSString*)name{
    
    NSString *imgPath = [[NSBundle mainBundle] pathForResource:name ofType:nil];
    
    if ( !imgPath ) {
        imgPath = [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
    }

    if (!imgPath) {
        imgPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@@2x" ,name] ofType:@"png"];
    }
    
    if (!imgPath) {
        imgPath = [[NSBundle mainBundle] pathForResource:name ofType:@"jpg"];
    }
    
    return [UIImage  initImmediateLoadWithContentsOfFile: imgPath];
}



+ (UIImage*) initImmediateLoadWithContentsOfFile:(NSString*)path {
    UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
    CGImageRef imageRef = [image CGImage];
    CGRect rect = CGRectMake(0.f, 0.f, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
    CGContextRef bitmapContext = CGBitmapContextCreate(NULL,
                                                       rect.size.width,
                                                       rect.size.height,
                                                       CGImageGetBitsPerComponent(imageRef),
                                                       CGImageGetBytesPerRow(imageRef),
                                                       CGImageGetColorSpace(imageRef),
                                                       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
                                                       );
    //kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little are the bit flags required so that the main thread doesn't have any conversions to do.
    
    CGContextDrawImage(bitmapContext, rect, imageRef);
    CGImageRef decompressedImageRef = CGBitmapContextCreateImage(bitmapContext);
    UIImage* decompressedImage = [[UIImage alloc] initWithCGImage: decompressedImageRef scale:2.0 orientation:UIImageOrientationUp];

    CGImageRelease(decompressedImageRef);
    CGContextRelease(bitmapContext);
    
    return decompressedImage;
}

   tableView: cellForRowAtIndexPath: 中的代码改为如下 

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        UIImage *tempImage = [UIImage imageWithName:self.imageNamesArray[indexPath.row]];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.imageView.image = tempImage;
            [cell setNeedsLayout];
            [cell layoutIfNeeded];
        });
    });
  • Tips:
  1.  imageNamed:的方式对图片名称要求比较松,可以自动识别2x、3x的图片,以及png不带后缀都可以;但是以[[NSBundle mainBundle] pathForResource:@"myCamera" ofType:@"png”] 如果图片是myCamera@2x的话,则获取的路径为空
  2. Instruments 底部的call tree 设置一般勾选第2、3、4项;call tree constraints 可以设置最小的耗时操作如16ms 
  3. Instruments 鼠标框选时间轴中的某部分可以只看选中区域的耗时操作;Option + Click 智能展开或折叠call tree
posted @ 2018-06-06 21:47  星红  阅读(323)  评论(0编辑  收藏  举报