需要重写URLProtocol协议,重新定义startLoading()方法,网络请求前尝试从本地获取,以便判断是否已缓存。若无,则发起请求,并缓存。
//检索缓存请求
func cachedResponseForCurrentRequest() ->NSManagedObject? {
//获取管理的数据上下文 对象
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
//创建一个NSFetchRequest,通过它得到对象模型实体:CachedURLResponse
let fetchRequest = NSFetchRequest()
let entity =NSEntityDescription.entity(forEntityName:"CachedURLResponse",
in: context)
fetchRequest.entity= entity
//设置查询条件
let predicate =NSPredicate(format:"url == %@",self.request.url!.absoluteString)
fetchRequest.predicate= predicate
//执行获取到的请求
do{
let possibleResult =trycontext.fetch(fetchRequest)
as? Array
if let result = possibleResult {
if !result.isEmpty{
returnresult[0]
}
}
}
catch{
print("获取缓存数据失败:\(error)")
}
returnnil
}
//开始处理这个请求
override func startLoading() {
requestCount+=1
print("Request请求\(requestCount): \(request.url!.absoluteString)")
//判断是否有本地缓存
let possibleCachedResponse =self.cachedResponseForCurrentRequest()
if let cachedResponse = possibleCachedResponse {
print("----- 从缓存中获取响应内容 -----")
//从本地缓中读取数据
let data = cachedResponse.value(forKey:"data")as!Data!
let mimeType = cachedResponse.value(forKey:"mimeType")as!String!
let encoding = cachedResponse.value(forKey:"encoding")as!String!
//创建一个NSURLResponse 对象用来存储数据。
letresponse =URLResponse(url:self.request.url!, mimeType: mimeType,
expectedContentLength: data!.count,
textEncodingName: encoding)
//将数据返回到客户端。然后调用URLProtocolDidFinishLoading方法来结束加载。
//(设置客户端的缓存存储策略.NotAllowed ,即让客户端做任何缓存的相关工作)
self.client!.urlProtocol(self, didReceive: response,
cacheStoragePolicy: .notAllowed)
self.client!.urlProtocol(self, didLoad: data!)
self.client!.urlProtocolDidFinishLoading(self)
}else{
//请求网络数据
print("===== 从网络获取响应内容 =====")
let newRequest = (self.request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
//NSURLProtocol接口的setProperty()方法可以给URL请求添加自定义属性。
//(这样把处理过的请求做个标记,下一次就不再处理了,避免无限循环请求)
URLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey",
in: newRequest)
//使用URLSession从网络获取数据
let defaultConfigObj =URLSessionConfiguration.default
let defaultSession = Foundation.URLSession(configuration: defaultConfigObj,
delegate:self, delegateQueue:nil)
self.dataTask= defaultSession.dataTask(with:self.request)
self.dataTask!.resume()
}
}
//保存获取到的请求响应数据
func saveCachedResponse () {
print("+++++ 将获取到的数据缓存起来 +++++")
//获取管理的数据上下文 对象
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
//创建NSManagedObject的实例,来匹配在.xcdatamodeld 文件中所对应的数据模型。
let cachedResponse = NSEntityDescription
.insertNewObject(forEntityName:"CachedURLResponse",
into: context)asNSManagedObject
cachedResponse.setValue(self.receivedData, forKey:"data")
cachedResponse.setValue(self.request.url!.absoluteString, forKey:"url")
cachedResponse.setValue(Date(), forKey:"timestamp")
cachedResponse.setValue(self.urlResponse?.mimeType, forKey:"mimeType")
cachedResponse.setValue(self.urlResponse?.textEncodingName, forKey:"encoding")
//保存(Core Data数据要放在主线程中保存,要不并发是容易崩溃)
DispatchQueue.main.async(execute: {
do{
trycontext.save()
}catch{
print("不能保存:\(error)")
}
})
}