使用TABAnimated集成骨架屏的開發者,大概都知道其原理是基於原視圖映射生成骨架層,在細節上不滿意的地方能夠經過預處理回調進行異步調整。java
緩存的是經過映射機制生成的骨架屏單元管理對象TABComponentManager
, 對該對象使用一個plist文件來解釋。同時,經過計數的方式,逐漸篩選出該用戶常常加載的骨架屏,提升緩存命中率。git
總體耗時:有緩存 <<< 無緩存 (圖不貼了,能夠自行評測)github
考慮到有些用戶主要關注對後續使用會有什麼影響,因此該點放到第一位。數組
TABAnimated新增closeCache
屬性。緩存
- debug 環境下,默認關閉緩存功能(爲了方便經過預處理回調調試)
- release 環境下,默認開啓緩存功能
- 若是你想在 debug 環境下測試緩存功能,能夠強制置爲NO。可是這個時候請注意,預處理回調再作修改,無效!
- 若是你始終都不想使用緩存功能,能夠強制置爲YES
下面是流程圖中相關說明:app
App在啓動時(圖左側),會預讀取對於該用戶來講加載次數最多的一部分數據到全局字典。框架
全局字典內容:key爲plist文件名,value爲解釋TABAnimatedManager
對象的plist文件內容異步
plist文件名用於惟一標識骨架屏管理對象。工具
起初,僅根據className惟一標識。可是有些class會在多個地方,不一樣adjustBlock
中出現,即這種方式沒法惟必定位某個骨架屏視圖。oop
最好的方式是將原視圖的className+預處理回調字符串化(學過java的應該都用過toString()吧),可是若是回調處理的東西過多,會浪費大量資源。
因而,採起的方案是:在啓動動畫後,獲取當前控制視圖(control view)的UIViewController
的className, 將其合併。
爲了描述加載次數最多
,引入了TABAnimatedCacheModel
, TABAnimatedCacheModel
一樣是用一個plist文件解釋。與TABAnimatedManager
同名
TABAnimatedCacheModel
的plist文件,大小約爲300bytesTABAnimatedManager
的plist文件,大小約爲3kbloadCount字段做用: App啓動後,讀取沙盒中全部的TABCacheModel
文件,根據loadCount
降序排列TABCacheModel
數組,並加載數組中前n個TABComponentManager
到內存中,存儲方式是全局字典。(n默認爲20)
loadCount更新機制: 啓動動畫後,在下一次runloop執行時,放到串行隊列中。
TABAnimatedCacheModel
計數,而不是TABAnimatedManager
自計數?一個用於解釋TABAnimatedManager
的plist文件大概是4kb,若是僅僅爲了更新一個字段頻繁寫入,很明顯浪費資源。 而TABAnimatedCacheModel
僅須要300bytes。
每次程序啓動時,都會讀取磁盤中全部解釋TABAnimatedCacheModel
的plist文件。經過TABAnimatedCacheModel
的loadCount,降序排列全部數據,而後將篩選後的前n條到全局字典中。(n默認爲20)
若是開發者在待發布的版本,對某個已經在沙盒中存在的plist文件,其對應視圖和預處理回調作了修改,此時須要從新寫入。因此在讀取緩存對象前,須要進行版本校對,若是不一致,須要從新使用映射機制。
太長不看😶😶???
TABAnimated
TABAnimated
文件夾裏生成2個文件夾cacheModel
和cacheManager
cacheModel
用於存儲TABAnimatedCacheModel
對象,該對象只有2個字段,一個用於索引cacheManager
,一個用於描述cacheManager
的加載次數,即loadCount
cacheManager
存儲的就是可以解釋骨架屏的骨架管理對象存儲路徑:沙盒根目錄/Document/TABAnimated/
默認會建立一個串行隊列,異步調度任務。
默認開闢一個常駐的子線程。該線程主要負責更新loadCount字段,寫入plist文件。經過添加NSMachPort
端口保證該線程的runLoop不會退出。(該處參考AFNetworking和SDWebImage)
字典自己的效率很高,並且用戶在本次使用app時,須要用到的骨架對象不會太多,因此字典效率大可放心。
loadCount字段只會在app啓動時用到,不須要急着去更新,因此線程的優先級設置爲NSQualityOfServiceBackground
。
在加載到新的(沙盒中沒有的)骨架對象,會當即寫入全局字典(即內存中),可是並不急着寫入沙盒,一樣地,此時將該任務交由已經建立好的異步隊列調度。
若是你的列表數據,須要針對row作特殊處理。 框架內部重寫了getter
方法,檢測到這種狀況後,會強制使用映射機制。
固然會有更好的處理方式,目前先這樣處理,不會存在太大的問題~