【圖像】FastImageCache 研究

概述

要點總結

  • FastImageCache 做了三件事:內存映射、解碼圖片、字節對齊
  • 內存映射是避免了內存復制。傳統的圖片使用方式中讀取一張圖片是先從磁盤讀取到內核緩沖區,再由內核緩沖區復制到用戶空間。內存映射免除了這一步復制。
  • 解碼圖片是避免的解碼過程。提前將圖片解碼成位圖,存儲在磁盤中。
  • 字節對齊是避免 Core Animation 在使用圖像數據前拷貝數據。Core Animation 使用的數據是需要對齊字節的,傳統過程中提供給 Core Animation 的數據未必是對齊的,那么就需要做一次拷貝將字節對齊。(還有一層含義,下文有詳細說明)

內存映射

解碼圖片

  • 這個地方的實現有點繞,首先創建一個 entry,這個 entry 內部的 bytes 已經做好內存映射了
  • 然后用 entry 的 bytes 創建一個 bitmap,這個位圖使用 bytes 中的數據,反過來如果我們在位圖中繪制內容,也會同步到 bytes 對應的內存中
  • 將圖片繪制到 bitmap 上,這相當于將已經解碼的圖片數據對應到 bytes 中,然后調用 entry 的 flush 方法,進行 mmap 機制的同步(即寫入磁盤)

字節對齊

  • 字節對齊有兩層含義,第一層是字節塊對齊,第二層是 Core Animation 使用圖像數據時的字節對齊(去除雜質)
  • 字節塊對齊處理的是 CPU 獲取字節塊時的優化工作,例如 CPU 需要獲取的數據在兩個字節塊中,CPU 就需要加載兩個字節塊,然后將需要的字節保留組成所需的字節塊,對齊后則直接加載所需的字節塊即可。
  • 在 FastImageCache 中是在 FICImageTableChunk 中實現的,據我不靠譜的觀察,字節塊對齊不需要額外的工作,圖像數據對齊后這里自動就對齊了
  • 使用圖像數據時的字節對齊是指,如果圖像數據的字節塊中包含雜質(例如一個字節塊 64 字節,其中有 60 字節是圖像數據,最后 4 字節是其它數據,對于 Core Animation 來說這 4 字節就是雜質),Core Animation 會復制這個字節塊的前 60 字節圖像數據,最后 4 字節以 0 填充
  • 圖像數據的對齊是用 FICByteAlignForCoreAnimation 實現的,有意思的是這里是按照圖像的行數據進行對齊,而不是整個圖像的數據進行對齊,猜測是繪制時是按行進行取用數據的,只有按行對齊才能避免 Core Animation 復制數據

使用流程

  • 我們來簡單總結一下 FastImageCache 是如何工作的
  • 核心類是 FICImageCache 和 FICImageTable,FICImageTable 是數據存儲的基本框架結構,FICImageCache 是管理類,我們主要與 FICImageCache 打交道
  • 我們通過 FICImageCache 的 retrieveImageForEntity 等方法獲取 image,取到后直接給 imageView 等組件賦值即可
  • 那么 FICImageCache 是如何獲取原始數據的呢?通過其 FICImageCacheDelegate 類型的代理獲取。這也是 FastImageCache 不夠方便的地方,我們需要自己實現代理方法,處理圖片下載等工作。
  • FICImageCache 通過代理拿到數據后調用 _processImage 方法來處理圖片,將圖片數據放在一個 FICEntityImageDrawingBlock 中傳遞給 imageTable 的 setEntryForEntityUUID 方法
  • 在 setEntryForEntityUUID 方法中,imageTable 會生成對應的 chunk 與 entry,使用 entry 的 bytes 創建位圖,使用傳進來的 FICEntityImageDrawingBlock 將圖像繪制在位圖上,那么解壓后的圖像數據就對應到了 bytes 中,然后調用 entry 的 flush 方法將數據映射回磁盤文件中
  • retrieveImageForEntity 方法內部真正獲取圖片的地方調用了 newImageForEntityUUID ,這里面就比較簡單了,找到對應的 entry,將其 bytes 轉換成 UIImage。這時候拿到的 UIImage 就是已經解壓過且字節對齊的數據了。

資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容