iOS性能优化iOS性能调优

iOS性能优化不归路~~圆角

2016-07-07  本文已影响2439人  LonelyBanana

<h4>一、前言</h6>

作为一名优秀的程序员应该具有极客思想,尽量把所有代码性能做到最优,但是在企业开发中如果没必要必须这样做还请不要一根筋,所有优化还是要看需求,不要过度优化导致项目延期,FaceBook 首席运营官 雪莉·桑德伯格在《向前一步》里的中心思想就是完成好过完美,成功就是尽可能做最好的选择,然后接受它们。


<h4>二、为什么会卡顿--摘录自ibireme大神的博客</h6>

通常来说,计算机系统中 CPU、GPU、显示器是以上面这种方式协同工作的。CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示,iOS也是一样的。

在最简单的情况下,帧缓冲区只有一个,这时帧缓冲区的读取和刷新都都会有比较大的效率问题。为了解决效率问题,显示系统通常会引入两个缓冲区,即双缓冲机制。在这种情况下,GPU 会预先渲染好一帧放入一个缓冲区内,让视频控制器读取,当下一帧渲染好后,GPU 会直接把视频控制器的指针指向第二个缓冲器。如此一来效率会有很大的提升。

双缓冲虽然能解决效率问题,但会引入一个新的问题。当视频控制器还未读取完成时,即屏幕内容刚显示一半时,GPU 将新的一帧内容提交到帧缓冲区并把两个缓冲区进行交换后,视频控制器就会把新的一帧数据的下半段显示到屏幕上,造成画面撕裂现象

为了解决这个问题,GPU 通常有一个机制叫做垂直同步(简写也是 V-Sync),当开启垂直同步后,GPU 会等待显示器的 VSync 信号发出后,才进行新的一帧渲染和缓冲区更新。这样能解决画面撕裂现象,也增加了画面流畅度,但需要消费更多的计算资源,也会带来部分延迟。

iOS使用的就是双缓冲机制,而安卓目前使用的是三缓冲机制。

<h5>那么卡顿的原因其实就显而易见了</h5>

img.png

在 VSync 信号到来后,系统图形服务会通过 CADisplayLink 等机制通知 App,App 主线程开始在 CPU 中计算显示内容,比如视图的创建、布局计算、图片解码、文本绘制等。随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU 进行变换、合成、渲染。随后 GPU 会把渲染结果提交到帧缓冲区去,等待下一次 VSync 信号到来时显示到屏幕上。由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。

从上面的图中可以看到,CPU 和 GPU 不论哪个阻碍了显示流程,都会造成掉帧现象。所以开发时,也需要分别对 CPU 和 GPU 压力进行评估和优化。


<h4>方法一:CAShapLayer设置蒙版从而实现圆角</h4>
直接上代码:

-(UIImageView *)imageView{
    if (!_imageView) {
        _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
        _imageView.image = [UIImage imageNamed:@"heiheihei.jpg"];
        _imageView.contentMode = UIViewContentModeScaleAspectFill;
    }
    return _imageView;
}
//初始化CAShapeLayer
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    //设置shapeLayer路径和圆角弧度
    shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:
                       self.imageView.bounds cornerRadius:40].CGPath;
    //设置ImageView的蒙版
    self.imageView.layer.mask = shapeLayer;
12CCDC74-AF95-438F-88B1-EF824F5167DA.png

然后这就完事了,但是这个方法主要占用的是GPU的资源,如果发现GPU本来占用资源就很高了,那么就不要用这个方法了。


<h4>方法二:直接渲染图片</h4>
第二种方法就是要直接把图片渲染成圆角,这种方法我认为应该是最优的圆角解决方案啦,如果还有别的方法请交流下。

-(UIImage *)getImageRadius:(CGFloat)radius andImage:(UIImage *)image{
    
    CGFloat scale = [UIScreen mainScreen].scale;
    UIGraphicsBeginImageContextWithOptions(image.size, NO, scale);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
    CGContextAddPath(c, path.CGPath);
    CGContextClip(c);
    [image drawInRect:rect];
    CGContextDrawPath(c, kCGPathFillStroke);
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}
A1549E84-F9DA-4EC1-9B5C-8459AAC6503A.png
上一篇下一篇

猜你喜欢

热点阅读