執行緒安全的 iOS 通用快取-SwiftlyCache

hlc123發表於2020-04-18

OS開發中或多或少都會使用到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寫在檔案中.

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章