iOS首頁渲染優化 -- imageName:
隨著APP功能的逐漸強大和業務上的逐漸完善,目前對於iOS開發者來說,對於APP的優化逐漸顯得尤為重要,本篇基於APP渲染優化上探討一下 imageName:
的愛恨情仇,下面以 UITabBarItem
渲染圖片為例,一步步以實踐的方式進行分析。
分析
首先看下未優化前的效果圖:
測試裝置:iPhone7 ,系統:12.1

細心的同學應該能夠發現,在登入進入首頁,到首頁渲染結束,中間會有一段白屏,為什麼會白屏一會而沒有馬上渲染首頁呢,第一感覺肯定是這中間形成主執行緒阻塞了,讓UI沒有立即渲染出來,其實事實上確實是這樣,那接下來我們通過 Instruments
分析一下哪裡執行了耗時操作以至於首頁渲染被阻塞了。 Instruments
裡面有個工具 TimeProfiler
,可以用來幫我們檢視哪裡有耗時操作。關於這個工具的使用和配置網上很多介紹本篇不做重點分析了,我直接粘除錯的圖片了。

通過TimeProfiler的結果一目瞭然,在CustomTabBarItem裡面做了什麼用了387ms。可以在工具裡面直接右鍵進入到到這段耗時程式碼的位置。我總共測試了五個tabbar渲染item圖片的耗時:


看打點日誌就很恐怖了,執行兩個 imageName:
就消耗了主執行緒差不多100ms的時間,五個 tabbar
那就是 500ms
的時間,顯然這就是上面效果圖出現白屏的原因了,實際上 imageName:
是會對圖片進行解碼之後再渲染的。
既然原因找到了,那就嘗試解決一下。將這個耗時的操作放到子執行緒執行,這裡也是參考了 SDWebImage
的圖片編解碼的思路, SD
在拿到圖片 data
的時候並沒有將它直接轉為 image
物件,而是在子執行緒裡面做了一個解碼的操作,這樣已經被解碼的圖片就賦值給 imageView
的時候就不會再進行解碼,也就不會妨礙主執行緒了。
- (void)decodedImageWithImageName:(NSString *)imageName block:(void(^)(UIImage *image))block { dispatch_async(dispatch_get_global_queue(0, 0), ^{ @autoreleasepool{ UIImage *image = [[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; image = [UIImage decodedImageWithImage:image]; dispatch_async(dispatch_get_main_queue(), ^{ if(block) block(image); }); } }); } 複製程式碼
程式碼實現很簡單,就是將圖片的操作放入到一個全域性佇列中,當然也可以自己建立一個佇列去執行這個非同步操作。 decodedImageWithImage:
為SD的程式碼,需要 #import "SDWebImageDecoder.h"
,具體實現網上對這一塊的原始碼解釋的比較多,很容易理解。
這樣我們的圖片經過這層處理之後,我們再來看一下優化之後的效果:

從總計500ms降到了6ms,基本可以忽略不及了,我們再在真機上面看一下優化後的效果:

總結
通過上面的分析,實際上 imageName:
這樣的 UI
函式我們天天都在用,但是從沒想過它在某些地方能產生這麼大的影響。問題的定位和解決其實都很簡單,但是這種簡單的問題往往會被我們開發者忽略掉,產生一些不好的結果,值得反思。