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来本身手动保存响应,并在请求发出后手动读取缓存,一切取舍看实际业务需求~
以上纯属我的理解,不免有误,如发现有错误的地方,欢迎评论指出,将第一时间修改,很是感谢~