為什么圖像在顯示到屏幕上之前要進(jìn)行解碼
一般我們使用的圖像是JPEG/PNG,這些圖像數(shù)據(jù)不是位圖,而是是經(jīng)過編碼壓縮后的數(shù)據(jù),需要線將它解碼轉(zhuǎn)成位圖數(shù)據(jù),然后才能把位圖渲染到屏幕上。
當(dāng)你用 UIImage 或 CGImageSource 的那幾個方法創(chuàng)建圖片時,圖片數(shù)據(jù)并不會立刻解碼。圖片設(shè)置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的數(shù)據(jù)才會得到解碼。這一步是發(fā)生在主線程的,并且不可避免。
iOS默認(rèn)是在主線程解碼,所以SDWebImage將這個過程放到子線程了。
同時因為位圖體積很大,所以磁盤緩存不會直接緩存位圖數(shù)據(jù),而是編碼壓縮后的PNG或JPG數(shù)據(jù)。
圖片加載的工作流
概括來說,從磁盤中加載一張圖片,并將它顯示到屏幕上,中間的主要工作流如下:
假設(shè)我們使用 +imageWithContentsOfFile: 方法從磁盤中加載一張圖片,這個時候的圖片并沒有解壓縮;
然后將生成的 UIImage 賦值給 UIImageView ;
接著一個隱式的 CATransaction 捕獲到了 UIImageView 圖層樹的變化;
在主線程的下一個 run loop 到來時,Core Animation 提交了這個隱式的 transaction ,這個過程可能會對圖片進(jìn)行 copy 操作,而受圖片是否字節(jié)對齊等因素的影響,這個 copy 操作可能會涉及以下部分或全部步驟:
分配內(nèi)存緩沖區(qū)用于管理文件 IO 和解壓縮操作;
將文件數(shù)據(jù)從磁盤讀到內(nèi)存中;
將壓縮的圖片數(shù)據(jù)解碼成未壓縮的位圖形式,這是一個非常耗時的 CPU 操作;
最后 Core Animation 使用未壓縮的位圖數(shù)據(jù)渲染 UIImageView 的圖層。
在上面的步驟中,我們提到了圖片的解壓縮是一個非常耗時的 CPU 操作,并且它默認(rèn)是在主線程中執(zhí)行的。那么當(dāng)需要加載的圖片比較多時,就會對我們應(yīng)用的響應(yīng)性造成嚴(yán)重的影響,尤其是在快速滑動的列表上,這個問題會表現(xiàn)得更加突出。
為什么要手動圖片解碼
加載優(yōu)化:
解壓是耗時的,而系統(tǒng)默認(rèn)是在主線程執(zhí)行,所以業(yè)界通常有一種做法是,異步強制解壓,也就是在異步線程主動將二進(jìn)制圖片數(shù)據(jù)解壓成位圖數(shù)據(jù),使用CGBitmapContextCreate(...)系列方法就能實現(xiàn)。
該處理方式在眾多圖片處理框架下都有體現(xiàn)。




