iOS 图片加载方式对比

一. 引言

我们做启动优化和卡顿优化的时候,发现图片通过不同的加载方式,加载时长相差巨大,尤其在低端机型(iPhone6iPhone7iPhone8系列)上,不同方式的图片加载,加载时间可以相差10几倍-几十倍不等,相差至少一个数量级。

试想一下,如果你做某个需求,添加了一些图片的加载,而这个图片加载耗时比较大,直接影响了启动时长和卡顿率,导致稳定性数据有大的下降,到时领导对你的印象和后期绩效评估,估计都会有影响。

因此充分了解图片加载的不同方式之间优缺点,加载的过程是非常有必要,有利于我们针对不同场景采用不同加载方式来提升项目稳定性。

我们都知道图片加载主要有三种方式:

  • 放在Assets.xcassets里面管理,然后通过imageNamed方法进行加载
  • 放在bundle里面通过imageNamed方法进行加载
  • 放在bundle里面通过imageWithContentsOfFile方式进行加载

这里我们对三种图片的加载速度进行一个对比,并分析下原因:

二. 实验

这里分别选了两组图片:

  • 一组是图片都是大图,大小在1.5M-4M之间,分辨率都是在1920*1080及以上。

    image.png

  • 另一组是小图,大小在1k-4k之间,分辨率在60*60左右。

然后分别将两组图片,放在Assets.xcassetsmain bundle里面。

image.png

放在main bundle的所有图片,加上前缀local

image.png

然后在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加载图片

以下是通过InstrumentsTime Profiler获取到的用Assets.xcassets管理通过 imageNamed加载图片堆栈。

Assets.xcassets管理通过 imageNamed首次加载图片:

image.png

Assets.xcassets管理通过 imageNamed非首次加载图片:

image.png

从堆栈我们可以看出imageNamed加载方法实际上调用的是一个叫做UIAssetManager的类,每个Bundle会有一个UIAssetManager,它有一个strong-strongNSMapTable的属性,用来做缓存,这个可以参考SDImageAssetManager

因此这里可以大概推断下用Assets.xcassets管理通过 imageNamed加载图片过程:

流程图.jpg

备注:
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继承下来的一种文件格式:

iOSmacOS操作系统,会通过私有库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加载

以下是通过InstrumentsTime Profiler获取到的用bundle管理通过 imageNamed加载图片的堆栈。

bundle管理通过 imageNamed首次加载图片的堆栈:

image.png
image.png

bundle管理通过 imageNamed非首次加载图片的堆栈:

image.png

通过这个调用堆栈,我们可以看出用bundle管理通过 imageNamed加载图片的过程如下:

bundle管理通过 imageNamed加载图片.jpg

从这个加载过程,我们可以分析出如下结论:

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里面,所以在获取renditionrenditionKey时多次调用canGetRenditionWithKeycanGetRenditionWithKey函数里面的通过renditionKey生成keySignature是一个copy操作和位操作,比较耗时,而且从从CUIMutableStructuredThemeStore的字典中取出rendition的操作添加了线程锁,导致耗时也相对高,由于图片资源并不再Assets.car,因此再重新通过mmap加载读取图片资源文件,形成renditionrenditionKey,总体耗时就比Assets.xcassets管理图片资源加载耗时高很多。

5. 用bundle管理通过 imageWithContentsOfFile加载

以下是通过InstrumentsTime Profiler获取到的用bundle管理通过 imageNamed加载图片堆栈。

bundle管理通过 imageWithContentsOfFile首次加载图片的堆栈:

image.png

bundle管理通过 imageWithContentsOfFile非首次加载图片的堆栈:

image.png

通过这个调用堆栈,我们可以看出用bundle管理通过 imageWithContentsOfFile加载图片的过程如下:

bundle管理通过 imageWithContentsOfFile加载图片.jpg

从这个加载过程,我们可以分析出如下结论:

A. 用bundle管理通过 imageWithContentsOfFile加载首次加载为什么耗时这么大

  • 首次加载,需要去初始化读取图片文件的相关环境,比如创建Reader_AVCI,加载CMPhotoSymbols等操作。

B. 为什么bundle管理通过 imageWithContentsOfFile加载图片耗时比用bundle管理通过 imageWithContentsOfFile加载图片小(非首次)

  • bundle管理通过 imageWithContentsOfFile加载图片不需要去Assets.car里面查询,没有生成renditionrenditionKey的相关操作和缓存操作,只有读取图片属性和图片资源的操作耗时。

四. 总结

1. 为什么Assets.xcassets管理通过 imageNamed加载耗时最少,用bundle管理通过 imageWithContentsOfFile加载耗时第二,用bundle管理通过 imageNamed加载,耗时最多。

  • Assets.xcassets编译形成的.car文件里面的资源信息是提前编译好的,当加载完.car文件解析之后,可以直接通过图片名称从.car文件解析后文件去获取图片属性和读取图片资源,没有多余操作。

  • bundle管理通过 imageWithContentsOfFile加载图片不需要去Assets.car里面查询,没有生成renditionrenditionKey的相关操作和缓存操作,只有读取图片属性和图片二进制的操作耗时

  • bundle管理通过 通过imageName的图片加载,需要先去Assets.car里面查询,由于图片资源并不再Assets.car里面,所以在获取renditionrenditionKey时多次调用canGetRenditionWithKeycanGetRenditionWithKey函数里面的通过renditionKey生成keySignature是一个copy操作和位操作,比较耗时,而且从从CUIMutableStructuredThemeStore的字典中取出rendition的操作添加了线程锁,导致耗时也相对高,由于图片资源并不再Assets.car,因此再重新通过mmap加载读取图片属性和图片资源,形成renditionrenditionKey,总体耗时最大。

2. 为什么放在bundle无论是通过imageNamed还是imageWithContentsOfFile来加载,为什么首次加载耗时都如此大。

  • 首次加载,需要去初始化读取图片文件的相关环境,比如创建Reader_AVCI,加载CMPhotoSymbols等操作。

五. 引用

Humble Assets Catalog
iOS拾遗—— Assets Catalogs 与 I/O 优化

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容