📄
Henry
  • Henry的神秘小屋
  • 其他
    • 字节码与机器码的区别?
  • ObjectiveC
    • NSInvocation
    • 检测OC项目中未使用的方法
    • Method Selector
    • 消息转发
  • Swift
    • 检测Swift项目中未使用的类 方法 属性
    • NSCoding
    • Mirror
    • JSONEncode JSONDecode
    • Any AnyObject AnyClass
    • is as? as! as
  • Cocoapods
    • 看懂Podfile.lock文件
    • 在编写的Pod中使用宏预编译
  • iOS
    • 苹果应用 保持画面流畅
    • 关于计算机展示图像的一些问题
    • @testable
    • iOS中URLRequest的缓存策略
    • CodePush接入流程
    • H5在WKWebView中读取沙盒文件
    • FDLog App客户端日志系统
    • 如何实现JSBridge基于WKWebView
    • 网络请求各个指标的度量
    • iOS13 UIModalPresentationStyle
    • 实现H5离线包机制
    • NSURLProtocol 拦截器
    • Framework
    • Lock
    • CFNetwork NSURLSession NSURLConnection
    • setNeedsLayout layoutIfNeeded layoutSubviews
    • StackView
    • Flutter Method Channel:从Dart到Native调用链
    • JSONSerialization.ReadingOptions
    • JSONSerialization.WritingOptions
    • RunLoop高级2
    • RunLoop高级1
    • RunLoop中级
    • RunLoop初级
    • LineBreak AutoShrink
    • 如何给H5出WebView调试包
    • TODO、FIXME、!!!、???、MARK
    • Operation的使用
    • UserDefault
    • 了解WKWebView
    • 输出日志信息到系统控制台
    • Float Double 失去精度问题
    • 使用xcodebuild命令打包导出
    • 在iOS项目中使用C++定义的模块
    • 证书问题
    • 创建常驻线程
  • 源码
    • 阅读PINCache源码
    • 解读AspectHook
    • HandyJSON是如何实现的?
  • 汇编
    • 看懂汇编
由 GitBook 提供支持
在本页
  • PINCache
  • 总结

这有帮助吗?

  1. 源码

阅读PINCache源码

上一页源码下一页解读AspectHook

最后更新于5年前

这有帮助吗?

前言: 这里我只介绍一下最核心的地方,至于很多细节并不提及,有兴趣的小伙伴可以查看源码

PINCache

PINCache 是一个 iOS 的三方开源库,提供了缓存的功能。 下面我们了解一下它的实现原理。 学习之前我们可以先了解 5 个东西

  • 项目结构

  • 内存缓存

  • 磁盘缓存

  • 线程安全

  • 清理机制

项目结构

下图展示了 PINCache 架构

  1. PINCache 提供的方法内部都是调用的 MemoryCache 或者 DiskCache,其实可以理解为 PINCache类 封装了 MemoryCache 和 DiskCache 两个类

  2. MemoryCache 和 DiskCache 也各自提供了自己的 Interface,如果开发者愿意的话 也可以根据自己情况单独调用 MemoryCache 和 DiskCache

内存缓存

内存缓存是其实就是持有一块内存不释放,然后对其添加要存储的对象,和清理要删除的对象。

优点:

  • 读取数据速度快 (因为内存缓存是内存对象)

缺点:

  • kill app 就被释放了,无法本地持久化存储。

  • 空间小,不能什么都放在内存,内存是寸土寸金的地方。

从上面的截图可以看出来,PINCache 内存缓存核心用的是 NSDictionary 对象来进行存储和读取的。

磁盘缓存

磁盘缓存是持久化存储,在 iOS 中一般就是存在沙盒中。

优点:

  • 可以持久化存储,App 被 Kill 也无妨。

  • 空间大

缺点:

  • 访问大数据的速度要慢与内存缓存。

下面是 PINCache 的磁盘缓存的实现逻辑,可以看出来,PINCache 磁盘缓存用了 NSKeyArchiver 和 NSKeyUnarchiver 来实现的对要存储对象的磁盘缓存。

它的存储步骤大致如下(读取相反):

  1. 用 Key+ 固定 URL 拼接成唯一的 FileURL

  2. 在把要存的对象 object 通过 NSKeyArchiver 序列化成 data

  3. 最后将 data 存入 fileURL 的沙盒路径下

线程安全

因为涉及线程安全有很多内容,这里只介绍一下 PINCache 的线程安全是如何处理的。

当程序中开启多线程时,并发的用 写 操作同一个变量的时候,会出现线程不安全,例如 同时 2 个线程同时对变量 A 进行 写 操作,虽然程序里的执行顺序是操作 A 早于操作 B,但是因为是多线程并发,实际执行的时候却是操作 B 早于操作 A,这样你的逻辑就出错了,本来你想的是用操作 B 的值覆盖掉操作 A,现在反过来了,甚至可能会 Crash。

解决这个问题有很多种方法,这里只看下 PINCache 的实现,PINCache 保障线程安全使用的是 条件锁 和 信号量, 下面是它的实现代码

不懂条件锁和信号量的童鞋可以单独查一下使用和区别。

这里说明一下: 正常情况,我们只需要保证写入就可以了,但是我们看到PINCache读取也使用了Lock,我们大致猜测,可能预防一些比较大的文件,正在写入或者写入一半的时候,这个时候去读取,会导致读取不完整的情况

清理机制

清理机制这里我就简单带过了 下面介绍几个 PINCache 里面的属性

  1. Date: 设置一个过期时间,当缓存内容超过这个日期,会被自动清理掉。

  2. Cost: 成本代价,未每个存储的 Value 设置一个 Cost,当总的 Cost>LimitCost 的时候会去清理缓存内容来平衡。

  3. ByteCount: 磁盘缓存的总字节大小,每次缓存的时候都会重新计算更新一次。

剩下一些机制,这里就不再介绍了,大家有兴趣看源码就好了。

总结

我们通过阅读 PINCache 的源码了解到核心的实现原理,如果你之前对缓存框架一头雾水,现在是不是清楚一些了呢。

在 PINCache 中,内存缓存使用的是 NSMutableDictionary

内存缓存: 信号量

磁盘缓存: 条件锁