不改一行代碼,就極大提高對(duì)本地圖片加載速度(對(duì) Asset 的探討)

2017年8月4日更新

根據(jù)這個(gè) Session Optimizing I/O for Performance and Battery Life 的描述,使用 Asset 還有對(duì)啟動(dòng)優(yōu)化的好處。

Asset Catalogs

10%的速度提升

如果你是被標(biāo)題吸引進(jìn)來的

可以直接跳到最后看結(jié)論,接下來是對(duì) Asset 為什么能加快對(duì)本地圖片加載速度的探討。

為什么探討 Asset 這個(gè)東西

由于項(xiàng)目中在剛啟動(dòng)的瞬間使用 "-[UIImage imageNamed:]" 會(huì)很慢,所以就打算探討 "-[UIImage imageNamed:]" 的實(shí)現(xiàn),但是過程中發(fā)現(xiàn)了使用 Asset 對(duì)于圖片的加載有極大的提升,就去探討 Asset 了。

使用 Time Profiler 探索實(shí)現(xiàn)

在使用 Time Profiler 調(diào)試 "-[UIImage imageNamed:]" 時(shí)候,發(fā)現(xiàn)它實(shí)際是調(diào)用 "-[UIImage imageNamed:inBundle:compatibleWithTraitCollection:]" 的,這時(shí)候萌發(fā)了一個(gè)想法是會(huì)不會(huì)根據(jù)指定 Bundle 的范圍會(huì)加快加載圖片的速度(理由是文件夾小了,減少索引次數(shù))。

實(shí)驗(yàn)后發(fā)現(xiàn),果然如此。把圖片分散到指定 bundle 后的速度大大提升了。

這時(shí)候,有同事提示我使用 Asset 會(huì)不會(huì)加快,因?yàn)?WWDC 有提到過。所以我就去看了這集 Session,發(fā)現(xiàn)它是這樣描述的。

發(fā)現(xiàn)使用 Asset 后速度也大大提升。到此為止就產(chǎn)生了探討 Asset 這個(gè)東西的需求了。

符號(hào)斷點(diǎn)跟蹤步驟

這里就用兩個(gè)圖片來簡(jiǎn)單描述 "-[UIImage imageNamed:]" 發(fā)生了什么?

左圖 Aseet/ 右圖 Folder
上圖 Aseet/ 下圖 Folder

使用 Asset 底層是使用一個(gè)叫 _UIAssetManager 的類去存取圖片,而使用 Folder 則是走 imageIO。而且即使你是用 Folder 也會(huì)先判斷 Asset 中沒有這張圖片才去走 imageIO 。

這里就不展開說,具體可以根據(jù)圖中的函數(shù)名下符號(hào)斷點(diǎn)跟蹤。(建議使用 chisel 來看各個(gè)類的成員變量)

緩存結(jié)構(gòu)和索引的不同

使用 Asset 的緩存結(jié)構(gòu)是: CUIStructuredThemeStore(https://github.com/billinghamj/iPhone6-iOS8-RuntimeHeaders/blob/master/PrivateFrameworks/CoreUI.framework/CUIStructuredThemeStore.h)

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

使用 Folder 的緩存結(jié)構(gòu)是: 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) -> 緩存
]

因?yàn)槭褂?Folder 去查找緩存,會(huì)先遍歷 nameIdentifierStore 查找是否有緩存,沒有就從 Folder 讀取。在 Time Profiler 會(huì)有那么多的 "isEqualTo" 比較。

而使用 Asset 則是直接根據(jù)圖片名稱來直接 "objectForKey:" 取出緩存。

兩者速度比較是: 前者 O(n)+O(1),后者 O(1)。
(至于為什么是O(n)? 因?yàn)槲矣^察有O(n)這個(gè)行為,且 "isEqualTo" 的參數(shù)剛好字典 keys 和當(dāng)前需要圖片的名字。)

而且看出來建立這個(gè)緩存的時(shí)候,使用 Asset 會(huì)快一點(diǎn)(只需要一個(gè)字典就可以)。

文件 IO 的不同

假設(shè)都是讀取 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 次數(shù)少了(如果數(shù)量大的話,比較更加明顯,Asset 一直是 1 次IO,而 Folder 會(huì)隨讀取文件的多少而遞增),而且在 IO Usage 可以看出讀取 Asset 的速度極快。

asset.car 到底是什么

asset.car 是編譯后打包到項(xiàng)目里的文件。從目前的研究來看,asset.car 其實(shí)是將資源打包并建立索引的二進(jìn)制文件,其頭部包含資源在二進(jìn)制對(duì)應(yīng)的位置(類似 seekTable)。

小結(jié)

所以使用 Asset 的速度快的原因有以下幾點(diǎn):

  1. 緩存格式較優(yōu),從而建立和查找緩存的速度也會(huì)加快。
  2. 圖片儲(chǔ)存方式較優(yōu),查找圖片位置更快,IO 也更快。

從 Folder 到 Asset,你需要做的只是轉(zhuǎn)移圖片資源(Xcode支持將Folder圖片一鍵導(dǎo)入),并且不需要改任何代碼就能使圖片加載速度大大加快。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,688評(píng)論 19 139
  • 在第13章“高效繪圖”中,我們研究了和Core Graphics繪圖相關(guān)的性能問題,以及如何修復(fù)。和繪圖性能相關(guān)緊...
    雪_晟閱讀 727評(píng)論 0 0
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,319評(píng)論 25 708
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,273評(píng)論 5 13
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 7,380評(píng)論 0 17

友情鏈接更多精彩內(nèi)容