線程安全的iOS通用緩存-SwiftlyCache

iOS開發中或多或少都會使用到Cache來減小網絡請求,在網絡上也有不少使用Objective-c開發的Cache框架,而Swift開發的Cache框架相對來講就要少一些,SwiftlyCache是我開發的一個Cache框架(github.com/hlc0000/Swi…)git

特性

  • 支持全部遵照Codable協議的數據類型
  • 支持LRU淘汰算法
  • 當收到內存警告或者App進入後臺時,內存緩存能夠配置爲自動清空或者手動清空
  • 支持使用Subscript,使讀寫數據更加方便
  • 提供了MultiCacheGenneratorMemoryCacheGeneratorDiskCacheGenerator用於支持for..incompactMapmapfilter等方法

架構圖:

3975951-c136f82df46be77c.png

成員職責劃分:

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中添加podSwiftlyCache
2.執行pod install或者pod update
3.導入SwiftlyCachegithub

手動導入:

1.下載SwiftlyCache文件夾內全部內容
2.將SwiftlyCache內的源文件添加到你的工程算法

屬性的使用:

MemoryCache可供使用的屬性:數據庫

設置最大的內存緩存容量(0爲不限制)swift

public var totalCostLimit:vm_size_t = 0api

設置最大的內存緩存數量緩存

public var totalCountLimit:vm_size_t = 0安全

系統內存警告是否刪除全部內存數據,默認爲truebash

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次)
圖1.jpg
PINMemoryCache寫入數據時採用三個字典的方式分別記錄緩存對象、緩存時間、緩存容量,在每次寫入數據時都須要依次對三個字典進行寫入操做.

YYMemoryCacheSwiftlyCache在每次寫入數據的時候最多隻須要對字典進行一次寫入操做.

在每次緩存數據完成以後,都須要丟棄超出TotalCountTotalCost的數據,PINMemoryCache在淘汰時都須要對Date字典從新進行排序,而後再丟棄掉最老的數據.

YYCacheSwiftlyCache則須要每次從鏈表的最後開始移除,YYCachecost淘汰是異步線程中進行的,而SwiftlyCache則是在當前線程中進行(每一次設置緩存數據完成後都會對TotalCost進行判斷,可丟棄數據不多,若是使用異步線程的開銷蠻大的).

單線程下的DiskCache性能測試(1000次,左側數據爲10k,右側數據爲100k)
圖2.png

PINDiskCache使用文件緩存數據,設置文件參數,文件的大小來管理緩存數據,對緩存數據的增刪改查也是轉化爲對文件的讀寫刪除操做.

YYDiskCacheSwiftlyCacheDiskCache都是使用SQLite和文件結合的方式進行數據緩存,能夠更好得擴展元數據,實現LRU淘汰算法,當緩存數據超過20k,將元數據寫入數據庫,value寫在文件中.

最後的話:

終於完成了最終版本的發佈了,我終於能夠去放肆的抽上一根菸了,哈哈哈,也但願各位小夥伴多多提出寶貴意見和建議....謝謝啦啦啦啦啦啦.......

相關文章
相關標籤/搜索