iOS 缓存

一、为什么使用缓存

缓存的目的是以空间换时间。

出于优化考虑:服务器压力、用户体验、用户流量等;

出于功能考虑:离线存储、微信会话列表、新闻列表等;

重度使用缓存的 APP:微信、微博等。

二、iOS 上的缓存框架

NSCache、PINCache、YYCache、SDWebImage(分析 SDImageCache 部分)

1、NSCache

苹果提供的一个简单的内存缓存;

类似 NSDictionary 一个可变的集合;

提供了可设置缓存大小与内存大小限制的方式;

保证了处理的数据的线程安全性;

内存警告时自动清理部分缓存数据

NSCache API

2、PINCache

PINCache 项目是在 Tumblr 宣布不再维护 TMCache 后,由 Pinterest 维护和改进的基于 TMCache 的一个内存缓存,修复了 TMCache 存在的性能和死锁问题。

3、YYCache

YYCache 是国内开发者 ibireme 开源的一个线程安全的高性能缓存组件。

4、SDWebImage

SDWebImage 框架通过给 UIImageView 和 UIButton 添加分类,实现了一个异步下载图片并且支持缓存的功能。整个框架的接口简洁,分工明确。

三、线程安全

这些缓存框架都是线程安全的。

多线程操作共享数据不会出现意想不到的结果就是线程安全的,否则则是不安全的。多个线程同时访问或读取同一共享数据,每个线程的读到的数据是一样的,则不存在线程不安全。如果多个线程对同一资源进行读写操作,那么每个线程读到的结果不可预料,线程是不安全的。

接下来:

1、iOS 中有哪些方法保证线程安全;

2、这些缓存框架是如何保证线程安全的。

四、iOS 开发中的锁

1、OSSPinLock

2、dispatch_semaphore

3、pthread_mutex  pthread_mutex(recursive)  NSRecursiveLock

4、NSLock

5、NSCondition  NSConditionLock

6、@synchronized

理解iOS开发中的锁

锁的性能

YYCache 和 PINCache 在内存缓存使用的是 pthread_mutex,在磁盘缓存使用的是Semaphone。 SDWebImage 在内存缓存使用的是 NSCache,本身就是线程安全的。在磁盘缓存使用串行队列来保证线程安全。

保证线程安全的方式

五、缓存

1、缓存的读取

缓存读取的逻辑大致为:

先访问内存缓存,再访问磁盘缓存(写入、读取、查询、删除);

读取缓存时,如果在内存缓存中无法获取对应的缓存,则会去磁盘缓存中寻找。如果在磁盘缓存中找到了对应的缓存,则会将该对象再次写入内存缓存中,保证下一次尝试获取同一缓存时能够在内存中就能返回,提高速度。

2、二级缓存

MemoryCache

PINMemoryCache 通过维护一个 dic 记录 object 最后一次访问的时间,通过排序来实现 LRU;

YYMemoryCache 缓存内部通过双向链表和 NSDictionary 实现 LRU 淘汰算法;

SDImageCache 缓存使用的是 NSCache。

DiskCache

PINDiskCache 和 SDImageCache 是基于文件系统的;

YYDiskCache 采用了 SQLite&文件系统实现。

3、SDWebImage

SDWebImage流程图

SDImageCache 默认图片清理时间为一周。

SDImageCache 缓存的写入:

1、将图片缓存在内存中;

2、判断图片格式是 png 或 jpeg,将图片转化为 NSData 数据;

3、如果是在 mac_os 系统中,直接将图片转化为 NSBitmapImageRep 数据;

4、获取图片的存储路径,其中图片的文件名通过传入的 key 经过 md5 加密后获得的;

5、将图片存储在磁盘中。

SDImageCache 缓存的删除:

1、获取磁盘中图片的最后修改日期;

2、根据日期将图片进行分类,将超过最长存放时间的文件存储在删除数组中,其他的文件信息存储在另一个 dic 中,并计算除去要删除的文件之外的文件大小;

3、根据删除数组中的文件路径,将对应的文件删除;

4、判断剩下的文件大小是否超过用户现在的最大容量;

5、如果超过,则将剩余文件按修改时间进行升序排列,删除修改时间最早的文件,直到剩余文件大小小于最大磁盘容量。

清理时机:

系统内存不足时,会将内存中所有的图片缓存删除;

当系统进入后台时,会对磁盘中的文件数据进行清理;

当收到程序关闭通知时,会对磁盘中的文件数据进行清理。

4、PINCache

PINCache 是线程安全的键值对缓存框架,用于缓存一些临时数据或需要频繁加载的数据。

类图

PINCache 除了可以按键取值、按键存值、按键删除值之外,还可以移除某个日期之外的缓存数据、删除所有缓存、限制缓存大小。

PINCacheAPI

PINMemoryCache:

维护了三个 dic,分别为_dictionary、_dates、_costs,字典的 key 相同,value 分别为对象、最后访问日期、大小。

清理缓存:

内存警告和进入后台时,默认自动清除所有的内存缓存。

PINDiskCache

PINDiskCache 以文件形式存储缓存,在内存中维护了两个  dic分别为 _dates、_sizes,分别存储了文件的最后编辑时间和文件大小。

在初始化时子线程遍历硬盘缓存初始化这两个值,开发中可以根据业务逻辑调用api删除硬盘缓存。

支持清理的维度:age、byte。

5、YYCache

YYCache:提供了最外层的接口,调用了 YYmemoryCache 和 YYDiskCache 的相关方法;

YYMemoryCache:负责处理容量小,相对高速的内存缓存。线程安全,支持手动和自动清理缓存等功能;

_YYLinkedMap:YYMemoryCache 使用的双向链表类;

_YYLinkedMapNode:是 _YYLinkedMap 使用的节点类;

YYDiskCache:负责处理容量大,相对低速的磁盘缓存。线程安全,支持异步操作,自动和手动清理缓存等功能;

YYKVStorage:YYDiskCache 的底层实现类,用于管理磁盘缓存;

YYKVStorageItem:内置在 YYKVStorage 中,是 YYKVStorage 内部用于封装某个缓存的类。

API

YYMemoryCache:

将需要缓存的对象与传入的 key 关联起来,类似于 NSCache。

不同于 NSCache 的是,它的内部有:

缓存淘汰算法:LRU 算法来淘汰使用频率较低的缓存;

缓存清理策略:三个维度分别为 count(缓存数量)、cost(开销)、age(距上一次的访问时间)。可根据不同的需求清理某一维度超标的缓存。

无论从哪一维度清理缓存,都是从使用频率最低的那个缓存开始清理。

在 YYMemoryCache 中,使用了双向链表来保存这些缓存:

当写入一个新的缓存时,要把这个缓存节点放到链表头部,并且原链表头部的缓存节点要变成现在链表的第二个节点;

当访问一个已有的缓存时,要把这个缓存节点移动到链表的头部,原位置两侧的缓存接上,原头部节点变为第二个;

(根据清理维度)自动清理缓存时,要从链表的最后端逐个清理。

清理缓存:

内存警告和进入后台时,默认自动清除所有的内存缓存。

YYDiskCache:

与第一级缓存相同点是:

都具有查询、写入、读取、删除缓存的接口;

不直接操作缓存,通过另一个类(YYKVStorage)来操作;

使用 LRU 算法来清理缓存;

支持 cost、count、age 三个维度清理不符合标准的缓存。

不同点是:

1、根据缓存数据的大小来采取不同的形式的缓存:

数据库 sqlite:针对小容量缓存,缓存的 data 和元数据都保存在数据库里;

文件+数据库形式:针对大容量缓存,缓存的 data 写在文件系统中,其元数据保存在数据库中。

2、除了 cost、count、age 三个维度,还添加了一个磁盘容量的维度。

六、缓存框架的选型

由图可见:

1、YYMemoryCache 的性能不错,仅次于 NSDictory+OSSpinLock;

2、NSCache 的写入性能较差。读写性能不错;

3、PINMemoryCache 的读写性能还可以,但读取速度差于 NSCache;


由图可见:

1、存取小数据时(NSNumber),YYDiskCache的性能远远高于基于文件存储的库;

2、较大数据的存取性能比较接近,但得益于 SQLite 存储的元数据,YYDiskCache 实现了 LRU 淘汰算法、更快的数据统计,更多的容量控制选项。

总结

1、选择合适的线程锁;

2、选择合适的数据结构;

3、选择合适的线程来操作不同的任务;

4、选择合适的存储方式;

5、选择底层的类;

6、变量、方法的命名以及接口的设计。

ppt:https://github.com/yuetianlu/cache_ppt

参考:

https://blog.ibireme.com/2015/10/26/yycache/

https://juejin.im/post/5a657a946fb9a01cb64ee761

https://juejin.im/post/5a4080d16fb9a0451969d0aa

https://www.cnblogs.com/fengmin/p/5318782.html

https://bestswifter.com/ios-lock/

http://www.cocoachina.com/ios/20171218/21570.html

https://blog.csdn.net/u012834750/article/details/69398216

你可能感兴趣的:(iOS 缓存)