返回顶部
首页 > 资讯 > 移动开发 >如何在iOS中高效的加载图片详解
  • 826
分享到

如何在iOS中高效的加载图片详解

ios加载图片 2022-05-25 14:05:24 826人浏览 泡泡鱼
摘要

目录前言图片的渲染流程DataBufferSD源码分析ImageBuffer占用内存大小Xcode测试如何减少图像占用内存向下采样SD源码分析解码过程选择正确的图片渲染格式渲染格式如

前言

iOS开发中,图片(UIImage)是我们在开发中,占用手机内存比较大的对象,如果在运行过程中,内存占用过大,对电池寿命会造成影响,如果超过了内存占用的最大值,会造成App的crash。这篇文章从图片的加载原理和SDWEBImage的源码实现的角度来介绍图片加载。

图片的渲染流程

ioS中使用 UIImage和UIImageView来记载图片,他俩遵守经典的mvc架构,UIImage相当于Model,UIImageView相当于View:

UIImage负责加载图片,UIImageView负责渲染图片。

图片的渲染流程分为3个阶段:加载(Load),解码(Decoder)和渲染(Render)

在每个阶段都会有相对应的缓冲区:数据缓冲区(DataBuffer),图像缓冲区(imageBuffer)和帧缓冲区(framebuffer)。

我们以加载一个图片的尺寸为:2048 px * 1536 px,在磁盘上的大小为:590kb的图片为例,来分析前两个阶段的缓冲区。

DataBuffer

DataBuffer只是一种包含一系列字节的缓冲区。通常以某些元数据开头,元数据描述了存储在数据缓冲区中的图像大小,包含图形数据本身,图像数据以某种形式编码 如 JPEG压缩或PNG,这意味着,该字节并不直接描述图像中像素的任何内容。此时的 DataBuffer大小为 590kb。

SD源码分析

在SDWebImage中,图片加载完成后,在 sd_imageFORMatForImageData的方法中,是通过DataBuffer的第一个字节来判断图片的格式的。


    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return SDImageFormatJPEG;
        case 0x89:
            return SDImageFormatPNG;
        case 0x47:
            retur SDImageFormatGIF;
        case 0x49:
        case 0x4D:
            return SDImageFormatTIFF;
        
        ......
   }

ImageBuffer

在图片加载完后,需要将Data Buffer的JPEG,PNG或其他编码的数据,转换为每个像素的图像信息,这个过程,称为Decoder(解码),将像素信息存放在ImageBuffer。

占用内存大小

图片占用的内存大小与图像的尺寸有关,与它的文件大小无关,在iOSSRGB显示格式中(4byte空间显示一个像素),如果解析所有的像素,需要 2048 px * 1536 px * 4 byte/px = 10MB的空间,此时的 ImageBuffer的大小为10MB。

在ImageBuffer解析完后,提交给frameBuffer进行渲染显示。

总的来说,图片加载过程和消耗的内存如下图所示:

Xcode测试

在Xcode工程中,当push新页面的时候,只加载一个图片。

加载前内存值:

加载后内存值:

大多数情况下,我们并不需要如此高精度的显示图片,占用了这么多的内存,能否减少加载图片时占用的内存值呢?

如何减少图像占用内存

向下采样

在苹果官方文档中,建议我们使用向下采样(Downsampleing)的技术,来加载图片,减少ImageBuffer的大小。

方法如下:


func downsample(imageAt imageURL: URL, to pointSize:CGSize, scale:CGFloat) ->UIImage {
    let imageSourcesOptions = [kCGImageSourceShouldCache: false] as CFDictionary

    let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourcesOptions)!
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    let downsampleOptions = [
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceShouldCacheImmediately: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceThumbnailMaxPixelSize:maxDimensionInPixels
        ] as CFDictionary
    let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
    
    return UIImage(cgImage: downsampledImage)
 }

我们来测试一下:


   let imageStr = Bundle.main.path(forResource: "view_site.jpeg", ofType: nil)
   let imageURL =  URL(string: "file://" + (imageStr ?? ""))
   guard let imgURL = imageURL else {
       return
   }
   imageView.image = downsample(imageAt:imgURL , to: CGSize(width: 200, height: 200), scale: UIScreen.main.scale)

加载之前时是13M,加载之后是 17M,效果是很明显的,节省了大约 5M的内存空间。

在对图片进行压缩时,我们应首选向下采样技术。

SD源码分析解码过程

在SDWebIamge中,一共有3种类型的解码器:SDImageiocoder, SDImageGIFCoder, SDImageAPNGCoder,根据DataBuffer的编码类型,使用相对应的编码器。

在 -(UIImage *)decodedImageWithData:(NSData *)data方法中,配置解码参数,开始进行解码操作。

在 + (UIImage *)createFrameAtIndex:(NSUInteger)index source:(CGImageSourceRef)source scale:(CGFloat)scale preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize options:(NSDictionary )options 中,完成图像解码

选择正确的图片渲染格式

渲染格式

在 iOS中,渲染图片格式有4种

  • Alpha 8 Format:1字节显示1像素,擅长显示单色调的图片。
  • Luminance and alpha 8 format: 亮度和 alpha 8 格式,2字节显示1像素,擅长显示有透明度的单色调图片。
  • SRGB Format: 4个字节显示1像素。
  • Wide Format: 广色域格式,8个字节显示1像素。适用于高精度图片,

如何正确的选择渲染格式

正确的思路是:不选择渲染格式,让渲染格式选择你。

使用 UIGraphicsImageRender来替换UIGraphicsBeginImageContextWithOptions,前者在iOS12以后,会自动选择渲染格式,后者默认都会选择SRGB Format。


func render() -> UIImage{
   let bounds = CGRect(x: 0, y: 0, width: 300, height: 100)
   let render = UIGraphicsImageRenderer(size: bounds.size)
   let image = render.image { context in
       UIColor.blue.setFill()
           let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: UIRectCorner.allCorners, cornerRadii: CGSize(width: 20, height: 20))
       path.addClip()
       UIRectFill(bounds)
    }
    return image
}

此时,系统为自动选择Alpha 8 Format格式,内容空间占用,将会减少75%。

减少后备存储器的使用

减少或者不使用 draw(rect:) 方法

在需要绘制带有子视图的View时,不使用 draw(rect:)方法,使用系统的View属性或者添加子视图的方式,将绘制工作交给系统来处理。

背景色直接通过UIView.backgroundColor设置,而非使用draw(rect:)

如何在列表中加载图片

我们在开发中,一般会对图片进行子线程异步加载,在后台进行 解码和下采样。在列表中,有时会加载很多图片,此时应该注意线程爆炸问题。

线程爆炸

当我们要求系统去做比CPU能够做的工作更多的工作时就会发生这种情况,比如我们要显示8张图片,但我们只有两个CPU,就不能一次完成所有这些工作,无法在不存在的CPU上进行并行处理,为了避免向一个全局队列中异步的分配任务时发生死,GCD将创建新线程来捕捉我们要求它所做的工作,然后CPU将花费大量时间,在这些线程之间进行切换,尝试在所有工作上取得我们要求操作系统为我们做的渐进式进展,在这些线程之间不停切换,实际上是相当大的开销,现在不是简单地将工作分派到全局异步队列之一,而是创建一个串行队列,在预取的方法中,异步的将工作分派到该队列,它的确意味着单个图像的加载,可能要比以前晚才能开始取得进展,但CPU将花费更少的时间,在它可以做的小任务之间来回切换。

在SDWebImage中,解码的队列  _coderQueue.maxConcurrentOperationCount = 1就是一个串行队列。这样就很好的解决了多图片异步解码时,线程爆炸问题。

总结

到此这篇关于如何在iOS中高效的加载图片的文章就介绍到这了,更多相关iOS高效加载图片内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 如何在iOS中高效的加载图片详解

本文链接: https://lsjlt.com/news/30510.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何在iOS中高效的加载图片详解
    目录前言图片的渲染流程DataBufferSD源码分析ImageBuffer占用内存大小Xcode测试如何减少图像占用内存向下采样SD源码分析解码过程选择正确的图片渲染格式渲染格式如...
    99+
    2022-05-25
    ios 加载 图片
  • 怎么在iOS中高效的加载图片
    这篇文章主要介绍怎么在iOS中高效的加载图片,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!图片的渲染流程在iOS中使用 UIImage和UIImageView来记载图片,他俩遵守经典的MVC架构,UIImage相当于...
    99+
    2023-06-25
  • ios开发UITableViewCell图片加载优化详解
    目录前言图片自适应比例XHWebImageAutoSize仅加载当前屏幕的内容预加载前言 我们平时用UITableView用的很多,所以对列表的优化也是很关注的。很多时候,我们设置U...
    99+
    2024-04-02
  • 详解Android 教你打造高效的图片加载框架
    1、概述 优秀的图片加载框架不要太多,什么UIL , Volley ,Picasso,Imageloader等等。但是作为一名合格的程序猿,必须懂其中的实现原理,于是乎,今天...
    99+
    2022-06-06
    图片 框架 Android
  • 在Teradata中如何进行高效的数据加载
    在Teradata中进行高效的数据加载可以通过以下几种方式实现: 使用Teradata Parallel Transporter...
    99+
    2024-04-02
  • 如何在Python中高效地加载LeetCode缓存?
    LeetCode是一个非常受欢迎的在线编程平台,它提供了大量的编程题目和算法练习题目。如果你是一名Python程序员,并且经常使用LeetCode平台,那么你可能会遇到一些性能问题,例如加载缓存数据的速度较慢。在本文中,我们将介绍一些方法,...
    99+
    2023-08-27
    load leetcode 缓存
  • 图片路径如何在Java web项目中加载
    本篇文章为大家展示了图片路径如何在Java web项目中加载,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。(1)   src="/image/1_it.jpg"...
    99+
    2023-05-31
    javaweb ava 目中
  • 如何在Android开发中利用Glide加载图片
    这期内容当中小编将会给大家带来有关如何在Android开发中利用Glide加载图片,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。添加依赖:compile 'com.github.bump...
    99+
    2023-05-31
    glide android roi
  • 如何在Java中实现高效的JavaScript和NumPy加载?
    在现代Web开发和数据科学中,JavaScript和NumPy已经成为两个非常重要的工具。然而,这两个工具的使用在Java中并不是那么简单,因为它们有很高的内存占用和加载时间。本文将介绍如何在Java中实现高效的JavaScript和Num...
    99+
    2023-10-18
    load javascript numpy
  • 如何在 Django 中实现高效的 Go 日志加载?
    Django 是一个开源的 Python Web 框架,广泛应用于Web开发中。在 Django 应用程序中,日志记录是非常重要的部分。在大型应用程序中,日志记录是必不可少的,因为它可以帮助我们跟踪应用程序的运行状态,诊断错误和性能问题。本...
    99+
    2023-11-12
    日志 load django
  • flutter中的资源和图片加载示例详解
    目录封面图指定相应的资源资源绑定 Asset bundling资源变体加载资源加载文本资源加载图片加载依赖包中的图片最后封面图 下个季度的目标是把前端监控相关的内容梳理出来,梳理出...
    99+
    2022-12-29
    flutter资源图片加载 flutter 资源图片
  • 如何在PHP中使用Memcached缓存技术提高图片的加载速度
    随着互联网的发展,网站的访问量越来越大,为了提高网站的性能和用户体验,缓存技术成为了必不可少的一部分。其中,Memcached是一种高性能的分布式缓存系统,广泛应用于互联网领域,特别适用于缓存大量的读操作。本文将介绍如何在PHP中使用Mem...
    99+
    2023-05-15
    PHP Memcached 缓存技术
  • 如何在html5中为图片添加动画效果
    本篇文章给大家分享的是有关如何在html5中为图片添加动画效果,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。html是什么html的全称为超文本标记语言,它是一种标记语言,包含...
    99+
    2023-06-06
  • 利用CSS、JavaScript及Ajax实现高效的图片预加载
    方法一:用CSS和JavaScript实现预加载 实现预加载图片有很多方法,包括使用CSS、JavaScript及两者的各种组合。这些技术可根据不同设计场景设计出相应的解决方案,十分...
    99+
    2022-11-15
    CSS JavaScript Ajax 图片预加载
  • Android不压缩图片如何实现高清加载巨图
    本篇内容主要讲解“Android不压缩图片如何实现高清加载巨图”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android不压缩图片如何实现高清加载巨图”吧!一、概述对于加载图片,大家都不陌生,...
    99+
    2023-07-02
  • 如何在ASP中实现高效的面试日志加载?
    在ASP.NET开发中,面试日志是一项非常重要的功能。在面试过程中,记录面试官和面试者的交流记录非常重要。但是,如果面试日志加载速度太慢,就会影响用户体验。因此,如何实现高效的面试日志加载是非常重要的。 下面,本文将介绍如何在ASP中实现高...
    99+
    2023-07-30
    load 面试 日志
  • 如何在Java中高效地加载大数据对象?
    Java作为一种广泛使用的编程语言,经常需要处理大量的数据对象,如何在Java中高效地加载大数据对象是一个非常重要的问题。本文将介绍一些在Java中高效加载大数据对象的方法,并提供一些示例代码。 一、使用Java序列化 Java序列化是一种...
    99+
    2023-08-16
    大数据 对象 load
  • PHP中如何高效地加载日志?
    PHP中如何高效地加载日志? 在开发过程中,日志是非常重要的一部分。它可以记录应用程序的运行状态、错误信息和警告信息等。在PHP应用程序中,日志通常被存储在文件中,但是如何高效地加载这些日志呢?本文将介绍一些PHP中高效加载日志的方法。 ...
    99+
    2023-10-08
    load 日志 开发技术
  • Javascript中如何实现图片的延迟加载
    这篇文章主要介绍Javascript中如何实现图片的延迟加载,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Javascript之图片的延迟加载的实例详解作用:保证页面打开的速度(3s...
    99+
    2024-04-02
  • JavaScript图片懒加载的优化方法详解
    目录一、方法一二、方法二 InterSectionObserver总结一、方法一 重点: 1.getBoundingClientRect().top > window.inn...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作