iOS图片加载渲染的优化

优化iOS图片加载:内存映射、异步解码与字节对齐

首先我们来看iOS加载一张图片所经历的过程:(下面所讲述的代码基本以      imageWithContentsOfFile 方法来举例)

数据加载

  1. 我们优先创建UIImageView,把获得的图像数据赋值UIImageView
  2. 识别到我们缓冲区没有数据,就会去从磁盘拷贝数据到缓冲区
  3. 然后加载我们的图片
  4. 拿到了图片,下面到了视图渲染

视图渲染

  1. 图片数据在CoreAnimation流水线中,执行如下流程
  2. 优先计算视图Frame,进行视图构建和图片格式转换
  3. 如果图像未解码,则优先解码成位图数据
  4. 进行打包处理,主线程Runloop将其提交给Render Server
  5. 在提交之前,如果数据没有字节对齐,CoreAnimation会再拷贝一份数据,进行字节对齐
  6. 然后经过GPU图形渲染管线处理以后将渲染结果放入帧缓冲区
  7. 然后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,给显示器显示

从上述渲染过程中,我寻找其可优化点。

  1. 图像解码
  2. 内存加载
  3. 对齐字节

1.图像解码

        当你用 UIImage 或 CGImageSource 的那几个方法创建图片时,图片数据并不会立刻解码。图片设置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的数据才会得到解码。这一步是发生在主线程的,并且不可避免。那么当需要加载的图片比较多时,就会对我们应用的响应性造成严重的影响,尤其是在快速滑动的列表上,这个问题会表现得更加突出。

        iOS默认会在主线程对图像进行解码。解码过程是一个相当复杂的任务,需要消耗非常长的时间。由于在主线程超过16.7ms的任务会引起掉帧,所以我们把解码操作从主线程移到子线程,让耗时的解码操作不占用主线程的时间,解码的核心方法如下:

CGContextRef CGBitmapContextCreate(
void * data, //这块内存用于存储被绘制的图形,这块内存的size最小不能小于bytesPerRow*height(图形每行的字节数乘以图形的高度),传递NULL意味着由这个函数来管理图形的内存,这可以减少内存泄漏的问题;
size_t width, //图形的width
size_t height,//图形的height
size_t bitsPerComponent, //像素的每个颜色分量使用的 bit 数,在 RGB 颜色空间下指定 8 即可
size_t bytesPerRow,//位图的每一行使用的字节数,大小至少为 width * bytes per pixel 字节。有意思的是,当我们指定 0 时,系统不仅会为我们自动计算,而且还会进行 cache line alignment 的优化
CGColorSpaceRef  _Nullable space, //就是我们前面提到的颜色空间,一般使用 RGB 即可;
uint32_t bitmapInfo//是一个枚举,
)

异步解码上代码

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
      NSString *imagePath = self.imagePaths;
      UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
      UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, YES, 0);
      [image drawInRect:imageView.bounds];
      image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      dispatch_async(dispatch_get_main_queue(), ^{
      });
  });

虽说能够正常解压,但是我们也会发现一个问题,就是大图片的解压,所以这个地方安装苹果和各大三方代码中的提示要分为2种情况讨论:

1.对于小于60M的图片我们直接对图片解码,下面是SD的代码


+ (UIImage *)decodedImageWithImage:(UIImage *)image {
    if (![self shouldDecodeImage:image]) {
        return image;
    }
    
    CGImageRef imageRef = [self CGImageCreateDecoded:image.CGImage];
    if (!imageRef) {
        return image;
    }
    UIImage *decodedImage = [[UIImage alloc] initWithC
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值