专栏首页大话swift线程安全的iOS通用缓存库-SwiftlyCache(推广)

线程安全的iOS通用缓存库-SwiftlyCache(推广)

iOS开发中或多或少都会使用到Cache来减少网络请求,在网络上也有很多使用Objective-c开发的Cache框架,而Swift开发的Cache框架相对来说就要少一些,所以我就用Swift 5开发了一款Cache库-SwiftlyCache(https://github.com/hlc0000/SwiftlyCache)

特性:

  • 支持所有遵守Codable协议的数据类型
  • 支持LRU淘汰算法
  • 当收到内存警告或者App进入后台时,内存缓存可以配置为自动清空或者手动清空
  • 支持使用Subscript,使读写数据更加方便
  • 提供了MultiCacheGenneratorMemoryCacheGeneratorDiskCacheGenerator用于支持for..incompactMapmapfilter等方法

架构图:

成员职责划分:

CacheAware:提供了一些基本接口的协议,MultiCache,MemoryCache,DiskCache等都遵守该协议. 
 
MultiCache:多重缓存,调用MemoryCache以及DiskCache相关方法. 
 
MemoryCache:负责处理容量小,相对高速的内存缓存,线程安全,支持异步操作,支持自动和手动清理缓存功能. 
 
MemoryStorage:MemoryCache使用的双向链表类. 
 
LinkedNode:双向链表节点类. 
 
DiskCache:负责处理容量大,相对低速的磁盘缓存,线程安全,支持异步操作,自动和手动清理缓存功能. 
 
DiskStorage:DiskCache内部实现类. 
 
DiskStorageItem:用于加载磁盘缓存数据使用的. 
 
SwiftlyCache支持使用Subscript,读写更加方便. 
 
SwiftlyCache提供了MultiCacheGenerator、MemoryCacheGenerator、DiskCacheGenerator用于支持for... in、compactMap、 map、filter等一系列方法

使用方法:

CocoaPods:

1.在Podfile中添加pod SwiftlyCache 2.执行pod install或者pod update 3.导入 SwiftlyCache

手动导入:

1.下载SwiftlyCache文件夹内所有内容 2.将SwiftlyCache内的源文件添加到你的工程

属性的使用:

MemoryCache可供使用的属性:

设置最大的内存缓存容量(0为不限制)

public var totalCostLimit:vm_size_t = 0

设置最大的内存缓存数量

public var totalCountLimit:vm_size_t = 0

系统内存警告是否删除所有内存数据,默认为true

public var autoRemoveAllObjectWhenMemoryWarning =true

进入后台是否删除所有内存数据,默认为true

public var autoRemoveAllObjectWhenEnterBackground =true

DiskCache可供使用的属性:

设置最大的磁盘缓存容量(0为不限制)

public var maxSize:vm_size_t = 0

设置最大的磁盘缓存数量

public var maxCountLimit:vm_size_t = 0

缓存的过期时间(默认是一周)

public var maxCachePeriodInSecond:TimeInterval = 60 * 60 * 24 * 7

自动检查时间设置(默认为120秒)

自动检查磁盘缓存是否达到限制,如果达到限制,则自动丢弃部分数据(缓存最大容量限制、缓存最大个数限制、数据是否过期)

public var autoInterval:TimeInterval = 120

接口的使用:

MultiCacheMemoryCache,DiskCache中的设置缓存、获取缓存、根据key查询是否存在对应的缓存数据、移除全部缓存数据、根据key移除对应的缓存数据都是遵守CacheAware协议的

设置缓存对象:(Value为所有遵守Codable协议的数据类型)

public funcset(forKey key: String, value: Value?, cost: vm_size_t = 0)->Bool
 
public funcset(forKey key:String,value:Value?,cost:vm_size_t = 0,completionHandler:@escaping((_ key:String,_ finished:Bool) -> Void))

可以通过Subscript的形势设置缓存keyValue

cache["key"] = Value

获取缓存对象

public func object(forKey key: String) -> Value?public func object(forKey key:String,completionHandler:@escaping((_ key:String,_ value:Value?) -> Void))

也可以通过Subscript的方式获取对应的缓存对象

let object = cache["key"]

根据给定的key查找缓存中是否存在对应的Value

public func isExistsObjectForKey(forKey key: String) -> Bool
 
public func isExistsObjectForKey(forKey key:String,completionHandler:@escaping((_ key:String,_ contain:Bool) -> Void))

根据key移除缓存中对应的value

public func removeObject(forKey key: String)

public func removeObject(forKey key: String, completionHandler: @escaping (() -> Void))

移除所有缓存

public func removeAll()public func removeAll(completionHandler:@escaping(() -> Void)

也可以通过for ... incompactMapmapfilter等方式获取到对应的缓存数据

public func makeIterator() -> MultiCacheGenerator
 
let iterator = cache.makeIterator()
 
while let result = iterator.next(){}
 
let flatMapResult = cache.compactMap{$0}
 
print("flatMapResult:\(flatMapResult)")
 
let filterResult = cache.filter{(key,object) -> Bool in return key =="shirley2"}
 
print("filterResult:\(filterResult)")
 
cache.forEach(print($0) )
 
let values = cache.map{return$0}
 
print("value:\(value)")
 
for(key,object) in cache{
 
 print("key:\(key),object:\(object)")
 
}

MultiCacheMemoryCache所有的可供使用的接口就介绍完了,DiskCache除了上述所有接口之外还有以下几个:

移除所有过期数据

public func removeAllExpired()->Bool{}

获取磁盘缓存总个数

public func getTotalItemCount()->Int}
 
public func getTotalItemCount(completionHandler:@escaping((_ count:Int)->Void)){}

获取磁盘缓存总占用容量

public func getTotalItemSize()->Int32{}
 
public func getTotalItemSize(completionHandler:@escaping((_ size:Int32)->Void)){}

性能对比:

之前也看过一些用Objective-c开发的Cache框架,比如PINCache,YYCache等,也基本了解了他们的一些优缺点,所以在SwiftlyCache中也尽量融合了他们的一些优点.

单线程下的MemoryCache性能测试(150000次)

PINMemoryCache写入数据时采用三个字典的方式分别记录缓存对象、缓存时间、缓存容量,在每次写入数据时都需要依次对三个字典进行写入操作.

YYMemoryCacheSwiftlyCache在每次写入数据的时候最多只需要对字典进行一次写入操作.

在每次缓存数据完成之后,都需要丢弃超出TotalCountTotalCost的数据,PINMemoryCache在淘汰时都需要对Date字典重新进行排序,然后再丢弃掉最老的数据.

YYCacheSwiftlyCache则需要每次从链表的最后开始移除,YYCachecost淘汰是异步线程中进行的,而SwiftlyCache则是在当前线程中进行(每一次设置缓存数据完成后都会对TotalCost进行判断,可丢弃数据很少,如果使用异步线程的开销蛮大的).

单线程下的DiskCache性能测试(1000次,左侧数据为10k,右侧数据为100k)

PINDiskCache使用文件缓存数据,设置文件参数,文件的大小来管理缓存数据,对缓存数据的增删改查也是转化为对文件的读写删除操作.

YYDiskCacheSwiftlyCacheDiskCache都是使用SQLite和文件结合的方式进行数据缓存,可以更好得扩展元数据,实现LRU淘汰算法,当缓存数据超过20k,将元数据写入数据库,value写在文件中.

本文分享自微信公众号 - 大话swift(gh_ca2266b7cab0),作者:佚名

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • gin框架之json输出

    目前json已经成为前后端交互的主要数据传输方式,那么gin框架是怎么输出json的呢?下面我们来讲讲在gin中是怎么输出json的。

    大话swift
  • MVP

    MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Present...

    大话swift
  • Android 集成百度地图那些事

    implementation files('libs/BaiduLBS_Android.jar')

    大话swift
  • Android 内存缓存:手把手教你学会LrhCache算法

    当 accessOrder 参数设置为true时,存储顺序(遍历顺序) = 外部访问顺序

    Carson.Ho
  • Guava 源码分析(Cache 原理)

    我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Google 大牛们是如何设计的。

    爱撸猫的杰
  • Google 出的 Guava 是个什么鬼?

    我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Google 大牛们是如何设计的。

    纯洁的微笑
  • 缓存的Cache Aside模式

    codecraft
  • 浏览器缓存机制剖析

    “缓存一直是前端优化的主战场,利用好缓存就成功了一半。本篇从HTTP请求和响应的头域入手,让你对浏览器缓存有个整体的概念。最终你会发现强缓存,协商缓存 和 启发...

    CSDN技术头条
  • Redis系列 | 缓存穿透、击穿、雪崩、预热、更新、降级

    Redis是高性能的分布式内存数据库,对于内存数据库经常会出现下面几种情况,也经常会出现在Redis面试题中:缓存穿透、缓存击穿、缓存雪崩、缓存预热、缓存更新、...

    王知无
  • 缓存及在 Python 中使用缓存

    缓存操作主要有两种类型。缓存如浏览器缓存,服务器缓存,代理缓存,硬件缓存工作原理的读写缓存。当处理缓存时,我们总是有大量的内存需要花费大量的时间来读写数据库、硬...

    Ewdager

扫码关注云+社区

领取腾讯云代金券