作者 | 杜玮,大学生/应届鲜鹅,iOS开发仔,业余时间会探店各种酒吧和调酒
早在 XCode 5,苹果引入了 Assets Catalogs ,它作为一个重要的开发组件,能够让开发者可以更方便的管理项目内的图片资源。
苹果也在不断的完善它的功能:
XCode 9 中添加了对颜色、矢量图、PDF等的支持(WWDC 2017 Session What’s New in Cocoa[1])
XCode 10 中添加了对
High Efficiency Image
和Mojave dark mode的支持(WWDC 2018 Session Optimizing App Assets[2])
那么相比直接存储在根目录下,究竟 Assets Catalogs 有什么自己独特的优势呢?在 WWDC 2016 上提到的 I/O 优化[3]是怎么完成的?imageName:
、imageWithContentOfFile:
这些方法在不同情况下又有什么表现呢,这篇文章就是基于这种种疑问诞生的。
太长不看版:
Assets Catalogs 将会在编译时生成一个.car文件,并在其中包含了这个图像加载所需的一切数据,当图像需要加载的时候,可以直接获取其中的数据并进行加载。
从一次 I/O 优化说起
相信大家现在在项目里面都会使用 Assets Catalogs 对图片资源进行管理,但很不幸,我接手的项目依然是把图片放在 Folder 中,这样看起来似乎并没有什么问题,但是如果打开 Time Profile ,就会发现把图片放在 Folder 中并使用imageName:
加载图片所用的耗时要比放在 Assets Catalogs 中要慢得多。
保存在 Folder ,并使用imageName:
获取:
展开后的调用栈耗时:
保存在 Assets Cataglogs ,并使用imageName:
获取:
展开后的调用栈耗时:
而如果使用imageWithContentOfFile:
,则两种存储方式所用的耗时则相同
使用imageWithContentOfFile:获取:
由这几个案例,我们可以推断出:
保存在 Folder 中并不会导致查找时间的增加,因为在
imageWithContentOfFile:
中两者加载图片的耗时一致使用
imageName:
加载图片时,两种存储方式都调用了底层 CoreUI.framework 的框架,但是调用的方法有所不同存储在 Folder 中的图片加载时生成的是
CUIMutableStructuredThemeStore
,而存储在 Assets Catalogs 中则是生成CUIStructuredThemeStore
CUIMutableStructuredThemeStore
与CUIStrucetedThemeStore
都调用到一些带有rendition字眼的类,而CUIMutableStrucetedThemeStore
还多了一层canGetRenditionWithKey:
的方法调用,导致了耗时的增加
从上面这些推断,我们可能会产生以下的一些问题:
CoreUI.framework 在加载图片中负责了什么工作?
CUIMutalbeStructuredThemeStore
与CUIStructuredThemeStore
是什么东西?rendition又是什么东西?
为什么 Assets Catalogs 能够提高这么多加载速度呢?
imageWithContentOfFile:
不对图像进行缓存,是否这个原因导致其加载速度要比imageWithName:
要快呢?
针对这些问题,我们一个一个解决。
探秘 Assets Catalogs 与 .car 文件
在研究这些问题之前,我们先来从新认识一下 Assets Catalogs。
关于 Assets Catalogs ,它详细的使用方法[4]相信大家已经很熟悉了,苹果也在Asset Catalog Format Reference[5]中给出了.xcassets
的组成。
但是可能很少人知道在 XCode 编译过程中,保存在 Assets Catalogs 中的图像资源并不是简单的复制到 APP 的 Bundle 中,而是会在编译时生成一个将资源打包并生成索引的.car
文件,而它在苹果开发者文档上并没有介绍,在网上关于它的信息也是少之又少。
那么.car
文件究竟是什么?
要知道.car
文件究竟是什么,有什么作用,我们可以先看看它包含了什么。所以我在 Assets Catalogs 中放入了一组PNG文件:
随后在 XCode 中对项目进行编译,在生成的 APP 包中我们可以找到编译完成的.car
文件。利用 AssetCatalogTinkerer 我们可以看