使用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
方法,检测到这种状况后,会强制使用映射机制。
固然会有更好的处理方式,目前先这样处理,不会存在太大的问题~