美文网首页Des's iOS 待阅读的文章iOS精品文章-性能优化(APM)
不改一行代码,就极大提高对本地图片加载速度(对 Asset 的探

不改一行代码,就极大提高对本地图片加载速度(对 Asset 的探

作者: Tsui_YuenHong | 来源:发表于2017-08-03 16:33 被阅读805次

2017年8月4日更新

根据这个 Session Optimizing I/O for Performance and Battery Life 的描述,使用 Asset 还有对启动优化的好处。

Asset Catalogs
10%的速度提升

如果你是被标题吸引进来的

可以直接跳到最后看结论,接下来是对 Asset 为什么能加快对本地图片加载速度的探讨。

为什么探讨 Asset 这个东西

由于项目中在刚启动的瞬间使用 "-[UIImage imageNamed:]" 会很慢,所以就打算探讨 "-[UIImage imageNamed:]" 的实现,但是过程中发现了使用 Asset 对于图片的加载有极大的提升,就去探讨 Asset 了。

使用 Time Profiler 探索实现

在使用 Time Profiler 调试 "-[UIImage imageNamed:]" 时候,发现它实际是调用 "-[UIImage imageNamed:inBundle:compatibleWithTraitCollection:]" 的,这时候萌发了一个想法是会不会根据指定 Bundle 的范围会加快加载图片的速度(理由是文件夹小了,减少索引次数)。

实验后发现,果然如此。把图片分散到指定 bundle 后的速度大大提升了。

这时候,有同事提示我使用 Asset 会不会加快,因为 WWDC 有提到过。所以我就去看了这集 Session,发现它是这样描述的。

发现使用 Asset 后速度也大大提升。到此为止就产生了探讨 Asset 这个东西的需求了。

符号断点跟踪步骤

这里就用两个图片来简单描述 "-[UIImage imageNamed:]" 发生了什么?

左图 Aseet/ 右图 Folder 上图 Aseet/ 下图 Folder

使用 Asset 底层是使用一个叫 _UIAssetManager 的类去存取图片,而使用 Folder 则是走 imageIO。而且即使你是用 Folder 也会先判断 Asset 中没有这张图片才去走 imageIO 。

这里就不展开说,具体可以根据图中的函数名下符号断点跟踪。(建议使用 chisel 来看各个类的成员变量)

缓存结构和索引的不同

使用 Asset 的缓存结构是: CUIStructuredThemeStore(https://github.com/billinghamj/iPhone6-iOS8-RuntimeHeaders/blob/master/PrivateFrameworks/CoreUI.framework/CUIStructuredThemeStore.h)

// _cache
[
Hash(A.png) -> 缓存
Hash(B.png) -> 缓存
]

使用 Folder 的缓存结构是: CUIMutableStructuredThemeStore(https://github.com/JaviSoto/iOS10-Runtime-Headers/blob/master/PrivateFrameworks/CoreUI.framework/CUIMutableStructuredThemeStore.h)

// nameIdentifierStore
[
A.png -> 1
B.png -> 2
]

// memoryStore
[
Hash_(1) -> 缓存
Hash_(2) -> 缓存
]

因为使用 Folder 去查找缓存,会先遍历 nameIdentifierStore 查找是否有缓存,没有就从 Folder 读取。在 Time Profiler 会有那么多的 "isEqualTo" 比较。

而使用 Asset 则是直接根据图片名称来直接 "objectForKey:" 取出缓存。

两者速度比较是: 前者 O(n)+O(1),后者 O(1)。
(至于为什么是O(n)? 因为我观察有O(n)这个行为,且 "isEqualTo" 的参数刚好字典 keys 和当前需要图片的名字。)

而且看出来建立这个缓存的时候,使用 Asset 会快一点(只需要一个字典就可以)。

文件 IO 的不同

假设都是读取 5 张图片

使用 Asset 的 IO 过程是:
open Asset -> read Asset -> close Asset

使用 Folder 的过程是:
open 1.png -> read 1.png -> close 1.png
open 2.png -> read 2.png -> close 2.png
open 3.png -> read 3.png -> close 3.png
open 4.png -> read 4.png -> close 4.png
open 5.png -> read 5.png -> close 5.png

可以看出这里 IO 次数少了(如果数量大的话,比较更加明显,Asset 一直是 1 次IO,而 Folder 会随读取文件的多少而递增),而且在 IO Usage 可以看出读取 Asset 的速度极快。

asset.car 到底是什么

asset.car 是编译后打包到项目里的文件。从目前的研究来看,asset.car 其实是将资源打包并建立索引的二进制文件,其头部包含资源在二进制对应的位置(类似 seekTable)。

小结

所以使用 Asset 的速度快的原因有以下几点:

  1. 缓存格式较优,从而建立和查找缓存的速度也会加快。
  2. 图片储存方式较优,查找图片位置更快,IO 也更快。

从 Folder 到 Asset,你需要做的只是转移图片资源(Xcode支持将Folder图片一键导入),并且不需要改任何代码就能使图片加载速度大大加快。

相关文章

  • 不改一行代码,就极大提高对本地图片加载速度(对 Asset 的探

    2017年8月4日更新 根据这个 Session Optimizing I/O for Performance a...

  • 图片懒加载

    原理: 按需加载图片,在图片位置滚动到浏览器窗口中时才去加载图片,这样可以减少网络请求提高网页加载速度-实现代码 ...

  • vue-lazyLoad的使用以及避坑

    图片懒加载可以极大程度的加快网页的加载速度,而且,使用非常简单,首先,安装插件 在main.js中进行引用,代码如...

  • Flutter常用组件Widget-Image

    显示图片的组件 以下是几种加载图片路径方式: Image.asset 加载asset项目资源中的文件 Image....

  • 3. Image组件

    Image Image.network(): 加载远程图片Image.asset(): 加载本地图片 显示网络图片...

  • lazyload懒加载的使用

    懒加载的意义(为什么要使用懒加载) 对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小,而代码也许...

  • 基础面试4

    3.vue怎么优化代码vue是组件化开发的,对代码优化主要是组件的按需加载,可以提高加载的速度,还有v-if,减少...

  • 三行代码让你网站加载快100倍!

    使用图片的懒加载! 对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小,而代码也许就只有几十KB。...

  • 图片懒加载

    什么是图片懒加载? 在图片非常多的应用场景,为了提高页面加载速度,改善用户体验,对未出现在视野范围内的图片先不进行...

  • 细说jQuery如何实现懒加载

    一、为什么需要懒加载? 对于图片过多的使用场景,为了提高页面加载速度,改善用户体验,我们对未出现在视野范围内的图片...

网友评论

  • Zz7777777:那我问下 那我在代码加载图片的时候 还是首先加载NSBundle 那个assets 然后在进行图片加载
    Zz7777777:@Tsui_YuenHong 就是在代码加载图片
    Tsui_YuenHong:@HelloCoders 没理解什么意思
  • ddaa8dae50b0:asset 现在支持本地化了不? 如果要提高速度, 我是不是得根据不同的语言,打成不同的bundle再加载?
  • Zz7777777:你的意思把所有图片打包放在Bundle里面进行加载
    Tsui_YuenHong:@HelloCoders 是的,我一开始也是从 bundle 测试发现加载很快,后来转移到 asset 的研究。但是根据官方的说明是 asset 存储更加“高效”,而且 asset 组织的图片会变成一个 asset.car 并且在这个 car 的头部会有一个索引。所以我认为 asset 优点更多。
    Zz7777777:@Tsui_YuenHong 我放在bundle 加载也很快啊
    Tsui_YuenHong:@HelloCoders 是放到 Assets 里面

本文标题:不改一行代码,就极大提高对本地图片加载速度(对 Asset 的探

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