Alamofire源碼學習(十三): Cache

往期導航:

Alamofire源碼學習目錄合集數據庫

ps: 時隔兩個月,忙成狗,終於有時間來繼續寫點東西了……swift

簡介:

上一篇是響應與解析,這篇是緩存,本體很簡單,也是用了接口隔離,主要是對HTTPCache的預處理,HTTP的緩存是經過響應頭中的相關字段來控制緩存相關參數,URLSession會自動管理緩存,Alamofire定義了一個CachedResponseHandler協議來對緩存進行了預處理,容許用戶在URLSession即將緩存響應數據前,對響應進行修改處理操做。api

URLSession中的緩存處理

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的抽象封裝與遍歷緩存管理器

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)
}
複製代碼

該協議有兩個類在使用:閉包

  1. SessionDelegate中聲明瞭SessionStateProvider協議,該協議中提供了全局的cacheResponseHandler,Session類遵循了該協議,在初始化時設置全局的cacheResponseHandler。
  2. Request基類中定義了可選變量cacheResponseHandler,能夠對單個請求使用專用的緩存處理器,優先級高於全局緩存處理器

而後在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

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來本身手動保存響應,並在請求發出後手動讀取緩存,一切取捨看實際業務需求~

以上純屬我的理解,不免有誤,如發現有錯誤的地方,歡迎評論指出,將第一時間修改,很是感謝~

相關文章
相關標籤/搜索