需要重寫(xiě)URLProtocol協(xié)議,重新定義startLoading()方法,網(wǎng)絡(luò)請(qǐng)求前嘗試從本地獲取,以便判斷是否已緩存。若無(wú),則發(fā)起請(qǐng)求,并緩存。
? ? //檢索緩存請(qǐng)求
? ? func cachedResponseForCurrentRequest() ->NSManagedObject? {
? ? ? ? //獲取管理的數(shù)據(jù)上下文 對(duì)象
? ? ? ? let app = UIApplication.shared.delegate as! AppDelegate
? ? ? ? let context = app.persistentContainer.viewContext
? ? ? ? //創(chuàng)建一個(gè)NSFetchRequest,通過(guò)它得到對(duì)象模型實(shí)體:CachedURLResponse
? ? ? ? let fetchRequest = NSFetchRequest()
? ? ? ? let entity =NSEntityDescription.entity(forEntityName:"CachedURLResponse",
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? in: context)
? ? ? ? fetchRequest.entity= entity
? ? ? ? //設(shè)置查詢條件
? ? ? ? let predicate =NSPredicate(format:"url == %@",self.request.url!.absoluteString)
? ? ? ? fetchRequest.predicate= predicate
? ? ? ? //執(zhí)行獲取到的請(qǐng)求
? ? ? ? do{
? ? ? ? ? ? let possibleResult =trycontext.fetch(fetchRequest)
? ? ? ? ? ? ? ? as? Array
? ? ? ? ? ? if let result = possibleResult {
? ? ? ? ? ? ? ? if !result.isEmpty{
? ? ? ? ? ? ? ? ? ? returnresult[0]
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? catch{
? ? ? ? ? ? print("獲取緩存數(shù)據(jù)失?。篭(error)")
? ? ? ? }
? ? ? ? returnnil
? ? }
//開(kāi)始處理這個(gè)請(qǐng)求
? ? override func startLoading() {
? ? ? ? requestCount+=1
? ? ? ? print("Request請(qǐng)求\(requestCount): \(request.url!.absoluteString)")
? ? ? ? //判斷是否有本地緩存
? ? ? ? let possibleCachedResponse =self.cachedResponseForCurrentRequest()
? ? ? ? if let cachedResponse = possibleCachedResponse {
? ? ? ? ? ? print("----- 從緩存中獲取響應(yīng)內(nèi)容 -----")
? ? ? ? ? ? //從本地緩中讀取數(shù)據(jù)
? ? ? ? ? ? let data = cachedResponse.value(forKey:"data")as!Data!
? ? ? ? ? ? let mimeType = cachedResponse.value(forKey:"mimeType")as!String!
? ? ? ? ? ? let encoding = cachedResponse.value(forKey:"encoding")as!String!
? ? ? ? ? ? //創(chuàng)建一個(gè)NSURLResponse 對(duì)象用來(lái)存儲(chǔ)數(shù)據(jù)。
? ? ? ? ? ? letresponse =URLResponse(url:self.request.url!, mimeType: mimeType,
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? expectedContentLength: data!.count,
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? textEncodingName: encoding)
? ? ? ? ? ? //將數(shù)據(jù)返回到客戶端。然后調(diào)用URLProtocolDidFinishLoading方法來(lái)結(jié)束加載。
? ? ? ? ? ? //(設(shè)置客戶端的緩存存儲(chǔ)策略.NotAllowed ,即讓客戶端做任何緩存的相關(guān)工作)
? ? ? ? ? ? self.client!.urlProtocol(self, didReceive: response,
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cacheStoragePolicy: .notAllowed)
? ? ? ? ? ? self.client!.urlProtocol(self, didLoad: data!)
? ? ? ? ? ? self.client!.urlProtocolDidFinishLoading(self)
? ? ? ? }else{
? ? ? ? ? ? //請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)
? ? ? ? ? ? print("===== 從網(wǎng)絡(luò)獲取響應(yīng)內(nèi)容 =====")
? ? ? ? ? ? let newRequest = (self.request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
? ? ? ? ? ? //NSURLProtocol接口的setProperty()方法可以給URL請(qǐng)求添加自定義屬性。
? ? ? ? ? ? //(這樣把處理過(guò)的請(qǐng)求做個(gè)標(biāo)記,下一次就不再處理了,避免無(wú)限循環(huán)請(qǐng)求)
? ? ? ? ? ? URLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? in: newRequest)
? ? ? ? ? ? //使用URLSession從網(wǎng)絡(luò)獲取數(shù)據(jù)
? ? ? ? ? ? let defaultConfigObj =URLSessionConfiguration.default
? ? ? ? ? ? let defaultSession = Foundation.URLSession(configuration: defaultConfigObj,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:self, delegateQueue:nil)
? ? ? ? ? ? self.dataTask= defaultSession.dataTask(with:self.request)
? ? ? ? ? ? self.dataTask!.resume()
? ? ? ? }
? ? }
? ? //保存獲取到的請(qǐng)求響應(yīng)數(shù)據(jù)
? ? func saveCachedResponse () {
? ? ? ? print("+++++ 將獲取到的數(shù)據(jù)緩存起來(lái) +++++")
? ? ? ? //獲取管理的數(shù)據(jù)上下文 對(duì)象
? ? ? ? let app = UIApplication.shared.delegate as! AppDelegate
? ? ? ? let context = app.persistentContainer.viewContext
? ? ? ? //創(chuàng)建NSManagedObject的實(shí)例,來(lái)匹配在.xcdatamodeld 文件中所對(duì)應(yīng)的數(shù)據(jù)模型。
? ? ? ? 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數(shù)據(jù)要放在主線程中保存,要不并發(fā)是容易崩潰)
? ? ? ? DispatchQueue.main.async(execute: {
? ? ? ? ? ? do{
? ? ? ? ? ? ? ? trycontext.save()
? ? ? ? ? ? }catch{
? ? ? ? ? ? ? ? print("不能保存:\(error)")
? ? ? ? ? ? }
? ? ? ? })
? ? }