美文网首页
iOS性能优化策略

iOS性能优化策略

作者: xymspace | 来源:发表于2020-04-23 18:07 被阅读0次

    解决卡顿

    卡顿产生原因:屏幕上每一帧内容,都是CPU计算后,GPU渲染的结果。当垂直信号(Vsync)产生时,如果CPU计算与GPU渲染的结果没有完成,屏幕会渲染上一帧的内容,从而发生丢帧。(按照60FPS的刷帧率,每隔16ms就会有一次VSync信号)。
    主要思路:尽可能减少CPU和GPU的资源消耗。

    具体方案:

    1. 在单元格高度不一的界面中,首先要根据数据结构,将单元格高度计算好,缓存在高度数组中,利用代理将对应高度返回。注意:不要频繁调用UIView的frame、transform、bounds,减少CPU的计算
    2. 可以用CALayer代替某些下划线之类的视图,或者用不到事件处理的地方,即尽量用轻量级对象。UIView之所以可以显示,是因为它有CALayer。除此之外UIView有处理事件的能力
    3. Auto layout会比直接设置frame消耗更多的CPU资源
    4. 圆角设置方式:
      1. 圆角使用CoreGraphics渲染
      2. 美工直接给圆角图片
      3. 比直接maskToBounds=YES; cornerRadius>0(二者同时设置)
        因为第3种是离屏渲染,需要再当前屏幕缓冲区以外开辟一个新的缓冲区进行渲染操作。离屏渲染的其他操作还有:layer.mask(遮罩)、layer.sgiykdRasterize=YES
    // 0.加载图片
        UIImage *image = [UIImage imageNamed:@"头像"];
        // 1.开启位图上下文,跟图片尺寸一样大
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
        // 2.设置圆形裁剪区域,正切与图片
        // 2.1创建圆形的路径
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
        // 2.2把路径设置为裁剪区域
        [path addClip];
        // 3.绘制图片
        [image drawAtPoint:CGPointZero];
        // 4.从上下文中获取图片
        UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
        // 5.关闭上下文
        UIGraphicsEndImageContext();
        _imageView.image = clipImage;
    
    // Graphics绘制方法
    - (void)drawCornerPicture{
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(200, 400, 200, 200)];
        imageView.image = [UIImage imageNamed:@"1"];
        // 开启图片上下文
        // UIGraphicsBeginImageContext(imageView.bounds.size);
        // 一般使用下面的方法
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0);
        // 绘制贝塞尔曲线
        UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:100];
        // 按绘制的贝塞尔曲线剪切
        [bezierPath addClip];
        // 画图
        [imageView drawRect:imageView.bounds];
        // 获取上下文中的图片
        imageView.image = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭图片上下文
        UIGraphicsEndImageContext();
        [self.view addSubview:imageView];
    }
    
    1. 图片的size最好和UIImageView的size保持一致,减少CPU的压缩计算
    2. 控制线程的最大并发量
    3. 尽量把耗时操作放入子线程,例如:
      1. boundingReactWithSize(计算文本)
      2. drawWithReact(文本绘制)
      3. 图片异步解码:[UIImage imageNamed:]返回的对象,只有当图片渲染时,才会被解码,而且这个解码方式在主线程。因此在异步处理好解码的结果直接渲染,可以减少耗时(图片解码)
    + (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
        if (![UIImage shouldDecodeImage:image]) {
            return image;
        }
    
        @autoreleasepool{
            
            CGImageRef imageRef = image.CGImage;
            CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];
            
            size_t width = CGImageGetWidth(imageRef);
            size_t height = CGImageGetHeight(imageRef);
            size_t bytesPerRow = kBytesPerPixel * width;
            // 图片绘制
            CGContextRef context = CGBitmapContextCreate(NULL,
                                                         width,
                                                         height,
                                                         kBitsPerComponent,
                                                         bytesPerRow,
                                                         colorspaceRef,
                                                         kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
            if (context == NULL) {
                return image;
            }
            // 绘制图片
            CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
            CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
             // 获取图片 ( 完成解码) 
            UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
                                                             scale:image.scale
                                                       orientation:image.imageOrientation];
            
            CGContextRelease(context);
            CGImageRelease(imageRefWithoutAlpha);
            
            return imageWithoutAlpha;
        }
    }
    
    + (BOOL)shouldDecodeImage:(nullable UIImage *)image {
        // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
        if (image == nil) {
            return NO;
        }
        if (image.images != nil) {
            return NO;
        }
        
        CGImageRef imageRef = image.CGImage;
        
        CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
        BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
                         alpha == kCGImageAlphaLast ||
                         alpha == kCGImageAlphaPremultipliedFirst ||
                         alpha == kCGImageAlphaPremultipliedLast);
        if (anyAlpha) {
            return NO;
        }
        
        return YES;
    }
    

    耗电优化

    1. 尽可能降低CPU、GPU功耗
    2. 少用定时器
    3. 优化I/O操作(文件读写)
      1. 尽量不要频繁写入小数据,最好批量一次性写入
      2. 访问大量数据,dispatch_io提供了基于GCD的异步操作文件I/O的API,可以优化磁盘访问
        3.数据较大用数据库

    网络优化

    1. 减少、压缩网络数据。(XML数据格式臃肿,所以JSON流行)
    2. 最好一次性下载完,减少请求次数。反之,使用断点续传,保障数据不重复请求
    3. 网络不可用时,停止执行所有网络请求

    定位优化

    1. 如果定位完成,最好关闭定位服务,这样可以让定位硬件断电
    2. 尽量不使用定位精度最高的KCLLocationAccuracyBest
    3. 需要后台定位时,尽量设置pauseLocationUpdatesAutomatically = YES;在用户很小移动时,会暂停位置更新

    相关文章

      网友评论

          本文标题:iOS性能优化策略

          本文链接:https://www.haomeiwen.com/subject/yjqaihtx.html