一. 引言
我们做启动优化和卡顿优化的时候,发现图片通过不同的加载方式,加载时长相差巨大,尤其在低端机型(iPhone6
、iPhone7
、iPhone8
系列)上,不同方式的图片加载,加载时间可以相差10几倍-几十倍
不等,相差至少一个数量级。
试想一下,如果你做某个需求,添加了一些图片的加载,而这个图片加载耗时比较大,直接影响了启动时长和卡顿率,导致稳定性数据有大的下降,到时领导对你的印象和后期绩效评估,估计都会有影响。
因此充分了解图片加载的不同方式之间优缺点,加载的过程是非常有必要,有利于我们针对不同场景采用不同加载方式来提升项目稳定性。
我们都知道图片加载主要有三种方式:
- 放在
Assets.xcassets
里面管理,然后通过imageNamed
方法进行加载 - 放在
bundle
里面通过imageNamed
方法进行加载 - 放在
bundle
里面通过imageWithContentsOfFile
方式进行加载
这里我们对三种图片的加载速度进行一个对比,并分析下原因:
二. 实验
这里分别选了两组图片:
-
一组是图片都是大图,大小在
1.5M-4M
之间,分辨率都是在1920*1080
及以上。
另一组是小图,大小在
1k-4k
之间,分辨率在60*60
左右。
然后分别将两组图片,放在Assets.xcassets
和main bundle
里面。
放在main bundle
的所有图片,加上前缀local
然后在FJFImageLocalLoadVC
里面创建三个
按钮分别是:
-
放在Assets.xcassets
管理通过imageNamed
来加载图片的Asset imageName
按钮 - 放在
bundle
管理通过imageNamed
来加载图片的文件夹 imageName
按钮 - 放在
bundle
管理通过imageWithContentsOfFile
来加载图片的文件夹 contentOfFile
按钮
每次启动,点击一个按钮,循环去加载对应的图片,并输出每张图片的加载耗时:
1. 大图实验数据
A. 用Assets.xcassets
管理通过 imageNamed
加载
2022-09-03 16:18:11.412898+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:7.09605 ms
2022-09-03 16:18:11.414388+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.95403 ms
2022-09-03 16:18:11.415612+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.86498 ms
2022-09-03 16:18:11.416765+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.79906 ms
2022-09-03 16:18:11.417784+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.71502 ms
2022-09-03 16:18:11.418706+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.64099 ms
2022-09-03 16:18:11.419683+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.72193 ms
2022-09-03 16:18:11.420537+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.59795 ms
2022-09-03 16:18:11.421399+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.60701 ms
2022-09-03 16:18:11.422386+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.73600 ms
2022-09-03 16:18:11.422987+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.30601 ms
2022-09-03 16:18:11.424036+0800 FJFBlogProjectDemo[15202:794425] --------Asset catalog加载图片 函数耗时:0.81706 ms
B. 用bundle
管理通过 imageNamed
加载
2022-09-03 16:19:55.879618+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:141.64495 ms
2022-09-03 16:19:55.886850+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:6.81698 ms
2022-09-03 16:19:55.892923+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:5.73993 ms
2022-09-03 16:19:55.897756+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:4.54497 ms
2022-09-03 16:19:55.900638+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.71297 ms
2022-09-03 16:19:55.902903+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.18391 ms
2022-09-03 16:19:55.905131+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.14791 ms
2022-09-03 16:19:55.907324+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.11704 ms
2022-09-03 16:19:55.909492+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.09796 ms
2022-09-03 16:19:55.911705+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.13397 ms
2022-09-03 16:19:55.913859+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.08092 ms
2022-09-03 16:19:55.916220+0800 FJFBlogProjectDemo[15217:795488] --------文件 imageName加载图片 函数耗时:2.28393 ms
C. 用bundle
管理通过 imageWithContentsOfFile
加载
2022-09-03 21:39:53.313360+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:122.10906 ms
2022-09-03 21:39:53.317499+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.84998 ms
2022-09-03 21:39:53.321495+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.74699 ms
2022-09-03 21:39:53.325367+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.62003 ms
2022-09-03 21:39:53.329069+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.44801 ms
2022-09-03 21:39:53.332854+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.51596 ms
2022-09-03 21:39:53.336646+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.54803 ms
2022-09-03 21:39:53.340615+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.70693 ms
2022-09-03 21:39:53.344022+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.15106 ms
2022-09-03 21:39:53.346476+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:2.30098 ms
2022-09-03 21:39:53.348315+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:1.73199 ms
2022-09-03 21:39:53.349933+0800 FJFBlogProjectDemo[18445:937441] --------文件 imageWithContentsOfFile加载图片 函数耗时:1.54901 ms
2. 小图实验数据
A. 用Assets.xcassets
管理通过 imageNamed
加载
2022-09-03 16:25:07.374076+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:4.29296 ms
2022-09-03 16:25:07.375350+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.88501 ms
2022-09-03 16:25:07.375836+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.23699 ms
2022-09-03 16:25:07.376785+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.75495 ms
2022-09-03 16:25:07.377780+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.76401 ms
2022-09-03 16:25:07.378743+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.72801 ms
2022-09-03 16:25:07.379187+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.20504 ms
2022-09-03 16:25:07.379620+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.25606 ms
2022-09-03 16:25:07.380062+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.27001 ms
2022-09-03 16:25:07.380984+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:0.73600 ms
2022-09-03 16:25:07.383440+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:2.22194 ms
2022-09-03 16:25:07.384820+0800 FJFBlogProjectDemo[15271:798689] --------Asset catalog加载图片 函数耗时:1.15597 ms
B. 用bundle
管理通过 imageNamed
加载
2022-09-03 16:27:19.256526+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:189.96501 ms
2022-09-03 16:27:19.266366+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:9.21297 ms
2022-09-03 16:27:19.273456+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:6.66499 ms
2022-09-03 16:27:19.278714+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:4.87900 ms
2022-09-03 16:27:19.283533+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:4.44400 ms
2022-09-03 16:27:19.287708+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:3.83902 ms
2022-09-03 16:27:19.290927+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:2.94399 ms
2022-09-03 16:27:19.292683+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:1.63591 ms
2022-09-03 16:27:19.294186+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:1.41799 ms
2022-09-03 16:27:19.295716+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:1.43397 ms
2022-09-03 16:27:19.296240+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:0.44703 ms
2022-09-03 16:27:19.296694+0800 FJFBlogProjectDemo[15289:800441] --------文件 imageName加载图片 函数耗时:0.39005 ms
C. 用bundle
管理通过 imageWithContentsOfFile
加载
2022-09-03 16:27:42.501943+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:160.00700 ms
2022-09-03 16:27:42.507223+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:4.72999 ms
2022-09-03 16:27:42.511637+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.99196 ms
2022-09-03 16:27:42.515078+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:3.05498 ms
2022-09-03 16:27:42.517940+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:2.53499 ms
2022-09-03 16:27:42.520895+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:2.61807 ms
2022-09-03 16:27:42.524116+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:2.92397 ms
2022-09-03 16:27:42.525691+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:1.39809 ms
2022-09-03 16:27:42.526938+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:1.10292 ms
2022-09-03 16:27:42.528083+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:1.03700 ms
2022-09-03 16:27:42.528171+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:0.01800 ms
2022-09-03 16:27:42.528236+0800 FJFBlogProjectDemo[15295:801035] --------文件 imageWithContentsOfFile加载图片 函数耗时:0.01597 ms
从以上的实验数据,我们取十次数据的平均值来看,我们可以得出以下几个结果:
相同图片,用
bundle
管理通过imageNamed
加载,耗时最多,无论是首次加载还是非首次。其次是用
bundle
管理通过imageWithContentsOfFile
加载耗时第二,首次加载耗时跟用bundle
管理通过imageNamed
加载相差不大,非首次加载耗时为用bundle
管理通过imageNamed
加载的耗时一半左右。用
Assets.xcassets
管理通过imageNamed
加载耗时最小,跟其他两者相比,都有至少1个量级的差距,无论是首次加载还是非首次加载。
因此从这个结果,可以得出如下几个问题:
- 为什么
Assets.xcassets
管理通过imageNamed
加载耗时最少,用bundle
管理通过imageWithContentsOfFile
加载耗时第二,用bundle
管理通过imageNamed
加载,耗时最多。 - 为什么放在
bundle
无论是通过imageNamed
还是imageWithContentsOfFile
来加载,为什么首次加载耗时都如此大。
三. 分析
带着上面的两个疑问,我们通过抓捕堆栈和阅读源码等来分析,为什么三种加载方式会产生差异的原因。
3. 用Assets.xcassets
管理通过 imageNamed
加载图片
以下是通过Instruments
的Time Profiler
获取到的用Assets.xcassets
管理通过 imageNamed
加载图片堆栈。
用Assets.xcassets
管理通过 imageNamed
首次加载图片:
用Assets.xcassets
管理通过 imageNamed
非首次加载图片:
从堆栈我们可以看出imageNamed
加载方法实际上调用的是一个叫做UIAssetManager
的类,每个Bundle
会有一个UIAssetManager
,它有一个strong-strong
的NSMapTable
的属性,用来做缓存,这个可以参考SDImageAssetManager
。
因此这里可以大概推断下用Assets.xcassets
管理通过 imageNamed
加载图片过程:
备注:
rendition是 CoreUI.framework 对某一图像资源的不同样式的统称,如@1x,@2x,每一个rendition有一个renditionKey与之对应,renditionKey包含了不同的attribute,用于记录图片资源的参数.
CUIMutalbeStructuredThemeStore与CUIStructuredThemeStore,可以理解为可变和不可变的图像集,包含了不同的图像资源。
从上面的分析我们也可以知道,用Assets.xcassets
管理通过 imageNamed
加载图片,首次加载图片之所以耗时比较多的原因:
- 首次加载,需要去打开并加载
Assets.car
文件,涉及到I/O
操作 - 需要
UIAssetManager
的初始化操作
那为什么通过Assets.car
加载图片资源,会比直接加载从bundle
上加载耗时少至少一个量级呢?
这就需要了解下.car
文件:
.xcassets
里面的所有资源在编译过程结束后会编译为.car
文件,而.car
文件实际上是一种特殊的bom
文件,而bom(Bill of Materials)
是从NeXTSTEP
继承下来的一种文件格式:
在iOS
和macOS
操作系统,会通过私有库CoreUI.framework
来解析car
文件,中间会调用Bom.framework
的接口来解析BOM
.
我们可以通过在命令行输入: assetutil -I Assets.car
, 查看Assets.car
文件内部结构
assetutil -I Assets.car
[
{
"Appearances" : {
"UIAppearanceAny" : 0
},
"AssetStorageVersion" : "Xcode 13.4 (13F17a) via AssetCatalogSimulatorAgent",
"Authoring Tool" : "@(#)PROGRAM:CoreThemeDefinition PROJECT:CoreThemeDefinition-520\n",
"CoreUIVersion" : 738,
"DumpToolVersion" : 738.1,
"Key Format" : [
"kCRThemeAppearanceName",
"kCRThemeLocalizationName",
"kCRThemeScaleName",
"kCRThemeIdiomName",
"kCRThemeSubtypeName",
"kCRThemeGlyphWeightName",
"kCRThemeGlyphSizeName",
"kCRThemeDimension2Name",
"kCRThemeDimension1Name",
"kCRThemeDeploymentTargetName",
"kCRThemeDisplayGamutName",
"kCRThemeDirectionName",
"kCRThemeSizeClassHorizontalName",
"kCRThemeSizeClassVerticalName",
"kCRThemeGraphicsClassName",
"kCRThemeMemoryClassName",
"kCRThemeIdentifierName",
"kCRThemeElementName",
"kCRThemePartName",
"kCRThemeStateName",
"kCRThemeValueName"
],
"MainVersion" : "@(#)PROGRAM:CoreUI PROJECT:CoreUI-738.1\n",
"Platform" : "ios",
"PlatformVersion" : "11.0",
"SchemaVersion" : 2,
"StorageVersion" : 17,
"ThinningParameters" : "optimized <idiom 1> <subtype 1792> <scale 2> <gamut 1> <graphics 6> <graphicsfallback (5,4,3,2,1,0)> <memory 4> <deployment 7> <hostedIdioms (4)>",
"Timestamp" : 1662280005
},
{
"AssetType" : "Image",
"BitsPerComponent" : 8,
"ColorModel" : "RGB",
"Colorspace" : "srgb",
"Compression" : "deepmap2",
"DeploymentTarget" : "2019",
"Encoding" : "ARGB",
"Idiom" : "universal",
"Name" : "little_icon_1",
"NameIdentifier" : 1592,
"Opaque" : false,
"PixelHeight" : 60,
"PixelWidth" : 60,
"RenditionName" : "little_icon_1.png",
"Scale" : 1,
"SHA1Digest" : "C161BEAD4ABCF455C8DFA2EF7901CF40EF40F2A5",
"SizeOnDisk" : 334,
"State" : "Normal",
"Template Mode" : "automatic",
"Value" : "Off"
},
从解析出来的json
我们可以看出,这个json
里面存储图片的所有基本信息,比如名称,宽高、大小,倍数,编码类型,压缩类型,颜色空间等。
我们知道加载图片,不仅要加载图片的二进制数据,还要加载图片相关的基本信息,这里通过Asset.car
来加载,可以在将Asset.car
解析之后,直接获取到图片的基本信息和加载图片的二进制。
A. 用Assets.xcassets
管理通过 imageNamed
首次加载为什么耗时相对较大原因
- 首次加载,需要去打开并加载
Assets.car
文件,涉及到I/O
操作 - 需要
UIAssetManager
的初始化操作
B. 用Assets.xcassets
管理通过 imageNamed
加载为什么耗时相对最小
-
Assets.xcassets
编译形成的.car
文件里面的资源信息是提前编译好的,当加载完.car
文件解析之后,可以直接通过图片名称从.car
文件解析后文件去定位读取图片属性和图片资源,没有多余操作。
4. 用bundle
管理通过 imageNamed
加载
以下是通过Instruments
的Time Profiler
获取到的用bundle
管理通过 imageNamed
加载图片的堆栈。
用bundle
管理通过 imageNamed
首次加载图片的堆栈:
用bundle
管理通过 imageNamed
非首次加载图片的堆栈:
通过这个调用堆栈,我们可以看出用bundle
管理通过 imageNamed
加载图片的过程如下:
从这个加载过程,我们可以分析出如下结论:
A. 用bundle
管理通过 imageNamed
加载首次加载为什么耗时这么大
- 首次加载,需要去打开并加载
Assets.car
文件,涉及到I/O
操作 - 需要
UIAssetManager
的初始化操作 - 需要去初始化读取图片文件的相关环境,比如创建Reader_AVCI,加载
CMPhotoSymbols
等读。
B. 为什么bundle
管理通过 imageNamed
加载图片耗时比用Assets.xcassets
管理通过 imageNamed
加载图片大(非首次)
-
Assets.xcassets
编译形成的.car
文件里面的资源信息是提前编译好的,可以直接定位去读取图片属性和图片资源,没有多余操作。 -
bundle
的图片加载,需要先去Assets.car
里面查询,由于图片资源并不再Assets.car
里面,所以在获取rendition
和renditionKey
时多次调用canGetRenditionWithKey
,canGetRenditionWithKey
函数里面的通过renditionKey
生成keySignature
是一个copy
操作和位操作,比较耗时,而且从从CUIMutableStructuredThemeStore
的字典中取出rendition
的操作添加了线程锁,导致耗时也相对高,由于图片资源并不再Assets.car
,因此再重新通过mmap
加载读取图片资源文件,形成rendition
和renditionKey
,总体耗时就比Assets.xcassets
管理图片资源加载耗时高很多。
5. 用bundle
管理通过 imageWithContentsOfFile
加载
以下是通过Instruments
的Time Profiler
获取到的用bundle
管理通过 imageNamed
加载图片堆栈。
用bundle
管理通过 imageWithContentsOfFile
首次加载图片的堆栈:
用bundle
管理通过 imageWithContentsOfFile
非首次加载图片的堆栈:
通过这个调用堆栈,我们可以看出用bundle
管理通过 imageWithContentsOfFile
加载图片的过程如下:
从这个加载过程,我们可以分析出如下结论:
A. 用bundle
管理通过 imageWithContentsOfFile
加载首次加载为什么耗时这么大
- 首次加载,需要去初始化读取图片文件的相关环境,比如创建
Reader_AVCI
,加载CMPhotoSymbols
等操作。
B. 为什么bundle
管理通过 imageWithContentsOfFile
加载图片耗时比用bundle
管理通过 imageWithContentsOfFile
加载图片小(非首次)
-
bundle
管理通过imageWithContentsOfFile
加载图片不需要去Assets.car
里面查询,没有生成rendition
和renditionKey
的相关操作和缓存操作,只有读取图片属性和图片资源的操作耗时。
四. 总结
1. 为什么Assets.xcassets
管理通过 imageNamed
加载耗时最少,用bundle
管理通过 imageWithContentsOfFile
加载耗时第二,用bundle
管理通过 imageNamed
加载,耗时最多。
Assets.xcassets
编译形成的.car
文件里面的资源信息是提前编译好的,当加载完.car
文件解析之后,可以直接通过图片名称从.car
文件解析后文件去获取图片属性和读取图片资源,没有多余操作。bundle
管理通过imageWithContentsOfFile
加载图片不需要去Assets.car
里面查询,没有生成rendition
和renditionKey
的相关操作和缓存操作,只有读取图片属性和图片二进制的操作耗时bundle
管理通过 通过imageName
的图片加载,需要先去Assets.car
里面查询,由于图片资源并不再Assets.car
里面,所以在获取rendition
和renditionKey
时多次调用canGetRenditionWithKey
,canGetRenditionWithKey
函数里面的通过renditionKey
生成keySignature
是一个copy
操作和位操作,比较耗时,而且从从CUIMutableStructuredThemeStore
的字典中取出rendition
的操作添加了线程锁,导致耗时也相对高,由于图片资源并不再Assets.car
,因此再重新通过mmap
加载读取图片属性和图片资源,形成rendition
和renditionKey
,总体耗时最大。
2. 为什么放在bundle
无论是通过imageNamed
还是imageWithContentsOfFile
来加载,为什么首次加载耗时都如此大。
- 首次加载,需要去初始化读取图片文件的相关环境,比如创建
Reader_AVCI
,加载CMPhotoSymbols
等操作。