Instruments的Core Animation进行性能优化

我们可以通过打开product->profile->Core Animation我们可以对app的进行一些优化。

  • 我们可以查看Core Animation的功能选项(九项)


    Instruments的Core Animation进行性能优化_第1张图片
    屏幕快照 2018-07-31 下午4.39.00.png

功能介绍

Color Blended Layers(图层混合)

  • 如果视图中的颜色混合越多,那么GPU通过混合纹理计算出像素的RGB值需要消耗的时间就越长,GPU的使用率就越高,可以通过减少颜色混合来提升滑动的流畅性.

  • 造成图层混合的原因
    1 控件透明度alpha不为1
    2 背景颜色backgroundColor不能为[UIColor clearColor]
    3 view的opaque为NO。(我也对这个属性摸不准,希望懂得人能告诉我)

  • 调试选项"Color Blended Layers"检测图层混合,发生图层混合的会变红色,没有的则显示为绿色。

Color Hits Green and MissesRed(光栅化)

  • 光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容进行缓存,可以得到一定幅度的性能提升。
// 将layer光栅化
label.layer.shouldRasterize = true

调试选项“Color Hits Green and Misses Red”,缓存命中为绿色,否则显示为红色。

Color Copied Images
  • 检查我们有无使用不正确图片格式,若是GPU不支持的色彩格式的图片则会标记为青色
  • 让UI和服务器给图的时候尽量给PNG格式的图片,至少我们项目中都是用的PNG。
Color Non-Standard Surface Formats (不标准的表面颜色格式)

打开这个选项,几乎Label和Button的titleLabel的背景颜色都会出现银白色,打开微信和的app也发现这个存在。

Color Immediately(颜色刷新频率)

使用此选项加快颜色刷新的频率。不过我们一般不用。

Color Misaligned Images(图片大小)

检查了图片是否被放缩,像素是否对齐。被缩放的图片会被标记为黄色,像素不对齐则会标注为紫色。这个在项目中也是经常出现。

Color Offscreen-Rendered Yellow(离屏渲染)

离屏渲染会先在屏幕外创建新缓冲区,离屏渲染结束后,再从离屏切到当前屏幕, 把离屏的渲染结果显示到当前屏幕上,这个上下文切换的过程是非常消耗性能的,实际开发中尽可能避免离屏渲染。

触发离屏渲染的行为

(1)drawRect:方法
(2)layer.shadow
(3)layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
(4)layer.shouldRasterize(光栅化)
(5)layer.mask
(6)layer.masksToBounds && layer.cornerRadius
  • 在项目开发中drawRect方法实际对性能损耗有点大,会造成CPU的使用率暴涨。我们能用CAShapeLayer替代的不去调用drawRect方法。
  • 用ShadowPath来替代shadowOffset绘制阴影,ShadowPath绘制不会造成离屏渲染。
  • layer.allowsGroupOpacity :子 layer 在视觉上的透明度的上限是其父 layer 的 opacity,为什么要开启这个,自己写的layer透明度自己没有b数么。
  • layer.allowsEdgeAntialiasing抗锯齿,如果你的layer被你缩放旋转造成出现锯齿,那么可以用这个属性,没办法。
  • layer.shouldRasterize开启光栅化会造成离屏渲染,所以在实际开发中我们要少用这个属性。
  • layer.mask,能不用就不用吧
  • layer.masksToBounds && layer.cornerRadius切圆角的方法有很多种,不要说只有这一种。
Color Compositing Fast-Path Blue(快速路径)

这个选项勾选后,由OpenGL compositor进行绘制的图层会标记为蓝色

  • Flash Updated Regoins
    这个选项会对重绘的内容高亮成黄色,重绘就是指使用Core Graphics绘制,绘制会损耗一定的性能,因此重绘区域应该越小越好。

开始优化

图层混合

Instruments的Core Animation进行性能优化_第2张图片
图层混合2.png

我们可以看出很多图片和label造成了图层的混合


label的图层混合原因
  • 默认的backgroundColor为nil.是个透明的样式。
@property(nullable, nonatomic,copy)            UIColor          *backgroundColor UI_APPEARANCE_SELECTOR; 
// default is nil. Can be useful with the appearance proxy on custom UIView subclasses.

如果没有给label添加一个backgroundColor,肯定会产生图层混合。

  • label的内容是中文,label实际渲染区域要大于label的size,最外层多了一个sublayer。
    所以需要给label添加
// masksToBounds默认为NO
label.layer.masksToBounds = YES;

我觉得我这个项目中的label都可以设置label.layer.masksToBounds,所以说干就干

  • 因为UIView的clipsToBounds属性没有关键字UI_APPEARANCE_SELECTOR,所以不能全局去设置裁剪。只有遵循UIAppearance的类并且设置UI_APPEARANCE_SELECTOR的属性才能去全局设置样式。

  • 用methodSwizzle来注入masksToBounds代码。

+ (void)load {
    Class class = [self class];
    // 取得函数名称
    SEL originSel = @selector(setText:);
    SEL swizzleSel = @selector(swizzleSetText:);

    Method originMethod = class_getInstanceMethod(class, originSel);
    Method swizzleMethod = class_getInstanceMethod(class, swizzleSel);

    BOOL addMethod = class_addMethod(class, originSel, method_getImplementation(swizzleMethod),method_getTypeEncoding(swizzleMethod));
    if (addMethod) {
        class_replaceMethod(class, swizzleSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    } else {
        method_exchangeImplementations(originMethod, swizzleMethod);
    }
}

- (void)swizzleSetText:(NSString *)text {
    [self swizzleSetText:text];
    self.layer.masksToBounds = YES;
}
  • backgroundColor背景颜色的设置,这个属性系统设置了UI_APPEARANCE_SELECTOR标识,所以我们可以全局设置,但是自身项目中可能会导致颜色重叠,所以我在需要去除图层混合的地方添加
// 一般白色
label.backgroundColor = [UIColor whiteColor];

image的图层混合

我发现UIGraphicsBeginImageContextWithOptions(<#CGSize size#>, <#BOOL opaque#>, <#CGFloat scale#>)的第二个参数,isOpaque 是用来决定透明通道是否被渲染。对没有透明度的图片设置这个参数为false,可能导致图片有粉红色调。

我用下面方法来切圆角,并解决图层混合

/**
 切圆角并解决图层混合
 
 @param fillColor 填充颜色
 @param cornerRadius 半径
 @param size 大小
 @return <#return value description#>
 */

- (UIImage *)imageRoundCornerWithFillColor:(UIColor *)fillColor cornerRadius:(CGFloat)cornerRadius size:(CGSize)size {
    // 设置为YES,解决离屏渲染解决的情况下,存在的图层混合
    if([[UIScreen mainScreen] scale] == 2.0){      // @2x
        UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
    }else if([[UIScreen mainScreen] scale] == 3.0){ // @3x ( iPhone 6plus 、iPhone 6s plus)
        UIGraphicsBeginImageContextWithOptions(size, YES, 3.0);
    }else{
        UIGraphicsBeginImageContext(size);
    }
    
    CGRect bounds = CGRectMake(0, 0, size.width, size.height);
    // UIGraphicsBeginImageContextWithOptions的opaque设置为YES后导致的四边黑色。
    [fillColor setFill];
    UIRectFill(bounds);
    
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius];
    [path addClip];
    [self drawInRect:bounds];
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
图层混合处理后
Instruments的Core Animation进行性能优化_第3张图片
图层混合处理后.png

Color Non-Standard Surface Formats(不标准的表面颜色格式)

Instruments的Core Animation进行性能优化_第4张图片
不标准的表面颜色格式.png

通过上面的图层混合解决处理后, Color Non-Standard Surface Formats的灰色区域也会随之去除。

Color Misaligned Images(图片大小)

图片Color Misaligned Images优化前.gif

上面是优化前出现的缩放的图片会被标记为黄色,像素不对齐则会标注为紫色。主要文字label或button也会出现像素不对齐的情况。

  • 网络图片被缩放很正常,我们要做的是尽量减少缩放和像素不对齐情况的发生。
    像素不对齐是指:视图或图片的点数(point),不能换算成整数的像素值(pixel),导致显示视图的时候需要对没对齐的边缘进行额外混合计算,影响性能。所有frame的取值尽量为证书,避免不必要的计算。
    图片标记为黄色的原因主要为:图片大小不对的造成的缩放
  1. 像素不对齐,利用ceilf()向上取整。防止frame为小数导致的性能损耗。
  2. tableView中头尾视图高度不能取值0.01,如果不需要就给个最小值CGFLOAT_MIN
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 
return CGFLOAT_MIN; 
} 

3 图片缩放(记得先解决图片像素不对齐的问题,如果有的话),再用上面的- (UIImage *)imageRoundCornerWithFillColor:(UIColor *)fillColor cornerRadius:(CGFloat)cornerRadius size:(CGSize)size方法去获取赋值(注意这个方法的图片相当于自适应填充)

Instruments的Core Animation进行性能优化_第5张图片
优化后.png
  • 优化后,那个箭头为黄色表示图片被缩放了,这是我的本地图片,我只要调整大小正确就会正常。

你可能感兴趣的:(Instruments的Core Animation进行性能优化)