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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容