iOS 从简单的4种网格绘制方法引申对性能的分析 --- 雯子Cyan

QrcodeView

  • 版本:V 1.0.0
  • 语言:object-c
  • GitHub:QrcodeView
  • 目录
  • 一. 起因
  • 二. 经过
  • 2.1. 卡顿方法-多个 CALayer 改变 frame
  • 2.2. 其他方法-多个 CAShapeLayer 绘制 path
  • 2.3. 卡顿方法-一个 CAShapeLayer 绘制 path
  • 2.4. 卡顿方法- CGContextRef 绘制
  • 2.5. 性能结果
  • 2.6. 题外话-二维码扫描
  • 三. 结果
  • 四. 原理分析

一. 起因

  • 看到图中的网格线你会想到怎么去画呢?(问设计要图不算!)
  • 今天隔壁的小伙伴碰上了一个 bug,就是扫描二维码的页面在ios 10 的手机上很卡,很卡。
  • 扫描用的是苹果原生的,动画效果用的 UIView animateWithDuration 改变线条位置(这个动画效果也是,其实用 CADisplayLink 这种感觉会更好)。
  • 分析了半天,最后发现原因既不是开启扫描的问题,也不是动画问题,而是那个网格绘制问题!(刚开始都没发现这货居然自己在绘制网格??)

二. 经过

2.1. 卡顿方法-多个 CALayer 改变 frame_

void (^addLineWidthRect)(CGRect rect) = ^(CGRect rect) {
            CALayer *layer = [[CALayer alloc] init];
            [self.scanImgV.layer addSublayer:layer];
            layer.frame = rect;
            layer.backgroundColor = [[[UIColor whiteColor]colorWithAlphaComponent:0.5] CGColor];
        };
        for (int i=0; i<widthView; i+=size) {
            addLineWidthRect(CGRectMake(i, 0, 0.5, heightView));
        }
        for (int i=0; i<heightView; i+=size) {
            addLineWidthRect(CGRectMake(0, i, widthView, 0.5));
        }
复制代码

2.2. 其他方法-多个 CAShapeLayer 绘制 path_

void (^addLineWidthRect)(CGPoint rect,CGPoint rects) = ^(CGPoint   rect,CGPoint rects) {
        UIBezierPath *pathLine = [UIBezierPath bezierPath];
        [pathLine moveToPoint:rect];
        [pathLine addLineToPoint:rects];

        CAShapeLayer *layerLine= [CAShapeLayer layer];
        layerLine.path=pathLine.CGPath;
        layerLine.lineWidth=0.5;
        layerLine.lineCap=kCALineCapRound;
        layerLine.strokeColor=[UIColor blueColor].CGColor;
        [self.scanImgV.layer addSublayer:layerLine];
    };

    for (int i=0; i<widthView; i+=size) {
        addLineWidthRect(CGPointMake(i, 0),CGPointMake(i, heightView));
    }
    for (int i=0; i<heightView; i+=size) {
        addLineWidthRect(CGPointMake(0, i),CGPointMake(widthView, i));
    }
复制代码

2.3. 卡顿方法-一个 CAShapeLayer 绘制 path_

UIBezierPath *pathLine = [UIBezierPath bezierPath];
    void (^addLineWidthRect)(CGPoint rect,CGPoint rects) = ^(CGPoint rect,CGPoint rects) {
        [pathLine moveToPoint:rect];
        [pathLine addLineToPoint:rects];
    };
    for (int i=0; i<widthView; i+=size) {
        addLineWidthRect(CGPointMake(i, 0),CGPointMake(i, heightView));
    }
    for (int i=0; i<heightView; i+=size) {
        addLineWidthRect(CGPointMake(0, i),CGPointMake(widthView, i));
    }
    CAShapeLayer *layerLine= [CAShapeLayer layer];
    layerLine.path=pathLine.CGPath;
    layerLine.lineWidth=0.5;
    layerLine.lineCap=kCALineCapRound;
    layerLine.strokeColor=[UIColor blueColor].CGColor;
    [self.scanImgV.layer addSublayer:layerLine];
复制代码

2.4. 卡顿方法- CGContextRef 绘制_

- (void)drawRect:(CGRect)rect {
    CGFloat widthView = CENTERRECT.size.width;
    CGFloat heightView = CENTERRECT.size.height;
    CGFloat size = 3;

    CGContextRef context =UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextSetFillColorWithColor(context,[UIColor blueColor].CGColor);

    for (int i=0; i<widthView; i+=size) {
        CGContextMoveToPoint(context,i+CENTERRECT.origin.x,+CENTERRECT.origin.y);
        CGContextAddLineToPoint(context,i+CENTERRECT.origin.x,heightView+CENTERRECT.origin.y);
    }
    for (int i=0; i<heightView; i+=size) {
        CGContextMoveToPoint(context,0+CENTERRECT.origin.x,i+CENTERRECT.origin.y);
        CGContextAddLineToPoint(context,widthView+CENTERRECT.origin.x,i+CENTERRECT.origin.y);
    }
    CGContextSetLineWidth(context,1.0);
    CGContextStrokePath(context);
    CGContextFillPath(context);
//    CGContextRestoreGState(context);
}
复制代码

2.5. 性能结果

绘制方法CPU 占用 %时间占用最大 %内存占用%
多个 CALayer4%35%0.74%
多个 CAShapeLayer4%12%0.74%
一个 CAShapeLayer4%9%0.74%
CGContextRef4%8%0.93%

2.6. 题外话-二维码扫描

#import <UIKit/UIKit.h>

@protocol QrcodeViewDelegate <NSObject>

/** 返回参数 */
-(void)QrcodeViewBackStr:(NSString *)backStr ifSuccess:(BOOL)ifSuccess;

@end

@interface QrcodeView : UIView

@property (nonatomic, weak)id<QrcodeViewDelegate>qrcodeViewDelegate;

/** 初始化 */
-(instancetype)initWithFrame:(CGRect)frame scanImg:(UIImage *)scanImg lineImg:(UIImage *)lineImg;

/** 是否创建头部 */
-(void)createTopView:(NSString *)TopStr backImg:(UIImage *)backImg;

/** 头部返回事件 */
@property (nonatomic) dispatch_block_t backBlock;

/** 重新扫描 */
-(void)reStartRunning;

@end
复制代码

三. 结果

  • 由图表数据看很明显,在时间占用上 CGContextRef 最少,紧随其后是一个 CAShapeLayer,而多个 CALayer 明显很不好。
  • 内存占用上 CGContextRef则显出其劣势。
  • 所以结论是一个 CAShapeLayer 对性能最好。??

四. 原理分析

  • DrawRect:DrawRect 属于 CoreGraphic 框架,占用 CPU,消耗性能大。
  • CAShapeLayer:CAShapeLayer 属于 CoreAnimation 框架,通过 GPU 来渲染图形,节省性能。动画渲染直接提交给手机GPU,不消耗内存。
  • 待续。。。

转载于:https://juejin.im/post/5bf6c0f2e51d4539921c327b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值