ps: 時隔兩個月,忙成狗,終於有時間來繼續寫點東西了……swift
上一篇是響應與解析,這篇是緩存,本體很簡單,也是用了接口隔離,主要是對HTTPCache的預處理,HTTP的緩存是經過響應頭中的相關字段來控制緩存相關參數,URLSession會自動管理緩存,Alamofire定義了一個CachedResponseHandler協議來對緩存進行了預處理,容許用戶在URLSession即將緩存響應數據前,對響應進行修改處理操做。api
URLSession的URLSessionDataDelegate中有聲明處理緩存的方法:緩存
/* Invoke the completion routine with a valid NSCachedURLResponse to * allow the resulting data to be cached, or pass nil to prevent * caching. Note that there is no guarantee that caching will be * attempted for a given resource, and you should not rely on this * message to receive the resource data. */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
複製代碼
URLSession會根據響應頭中的Cache相關字段自行處理緩存,使用接口提供給用戶修改緩存的機會,改方法容許用戶在緩存響應數據前,對響應數據進行修改,修改完成後必需要調用completionHandle,入參不爲空則緩存參數緩存數據,入參爲空則不緩存該響應。markdown
Alamofire定義了CachedResponseHandler協議來處理緩存操做,該協議只有一個方法:session
public protocol CachedResponseHandler {
/// 決定緩存處理操做
///
/// completion回調參數有三種狀況:
/// 1.入參的第二個參數(不改變數據,直接緩存,默認行爲)
/// 2.對response緩存數據修改後的新數據(適合須要對數據進行修改後再緩存)
/// 3.nil,不緩存respose
///
///
/// - Parameters:
/// - task: 請求task
/// - response: 即將要緩存的響應數據
/// - completion: 決定緩存行爲的完成回調
func dataTask(_ task: URLSessionDataTask, willCacheResponse response: CachedURLResponse, completion: @escaping (CachedURLResponse?) -> Void)
}
複製代碼
該協議有兩個類在使用:閉包
而後在SessionDelegate實現的URLSessionDataDelegate的緩存處理方法中,使用潛在的緩存處理器來處理緩存app
//處理是否保存緩存
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) {
//通知監聽器
eventMonitor?.urlSession(session, dataTask: dataTask, willCacheResponse: proposedResponse)
//先獲取Request的緩存處理器,爲空再去獲取Session的全局緩存處理器
if let handler = stateProvider?.request(for: dataTask)?.cachedResponseHandler ?? stateProvider?.cachedResponseHandler {
//用緩存處理器處理緩存
handler.dataTask(dataTask, willCacheResponse: proposedResponse, completion: completionHandler)
} else {
//沒有緩存處理器的話,採用默認邏輯處理緩存
completionHandler(proposedResponse)
}
}
複製代碼
Alamofire中定義了個ResponseCacher,這是個簡易的緩存處理器,其中定義了一個枚舉Behavior,能夠決定保存緩存的邏輯:ide
public struct ResponseCacher {
/// 定義處理緩存的行爲
public enum Behavior {
/// 緩存原始數據
case cache
/// 不緩存
case doNotCache
/// 先修改數據,再緩存新的數據,參數爲修改數據的閉包,改閉包返回可選的新緩存數據
case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)
}
/// 快速初始化緩存原始數據的對象
public static let cache = ResponseCacher(behavior: .cache)
/// 快速初始化不緩存的對象
public static let doNotCache = ResponseCacher(behavior: .doNotCache)
/// 緩存行爲
public let behavior: Behavior
/// 初始化
public init(behavior: Behavior) {
self.behavior = behavior
}
}
複製代碼
接着擴展ResposeCacher,實現CachedResponseHandler協議,根據Behavior的類型來調用completion回調post
extension ResponseCacher: CachedResponseHandler {
public func dataTask(_ task: URLSessionDataTask, willCacheResponse response: CachedURLResponse, completion: @escaping (CachedURLResponse?) -> Void) {
switch behavior {
case .cache:
//緩存原始數據,直接傳原始數據給completion
completion(response)
case .doNotCache:
//不緩存數據,傳nil給completion
completion(nil)
case let .modify(closure):
//修改,先調用參數closure獲取修改數據,而後傳給completion
let response = closure(task, response)
completion(response)
}
}
}
複製代碼
Alamofire中對於緩存的處理只是作了簡單的抽象封裝,把本來須要代理處理的操做,包裝成了是用協議對象來處理,咱們用的時候,能夠簡單的直接使用ResponseCacher,也能夠本身針對本身的業務邏輯實現本身的緩存處理器,十分靈活。
不過URLSession的緩存處理,依賴於響應頭中的緩存參數,所以像緩存的有效期,認證等,更多須要依賴於後臺處理,若是須要app自行緩存所有數據到本地數據庫,那就須要使用EventModifier + RequestAdapter來本身手動保存響應,並在請求發出後手動讀取緩存,一切取捨看實際業務需求~
以上純屬我的理解,不免有誤,如發現有錯誤的地方,歡迎評論指出,將第一時間修改,很是感謝~