When I receive a HTTP Status Code 304 from my server, the server doesn't send any content data, because nothing changed.
Now I want to use the cache control from Alamofire 4 (for Swift 3). But I can't figure out how does it work. I find some examples for Alamofire 3 here
Alamofire.request(req)
.response {(request, res, data, error) in
let cachedURLResponse = NSCachedURLResponse(response: res!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)
}
So I think the structure will be similar in Alamofire 4. But where is my content saved? I was hoping that I can do something like this
Pseudocode:
if response.statusCode == 304 {
return cacheControl.response
}
Does anybody have an idea? In doubt I have write it on my own.
I managed to recover the old cache contents in case the Status code is 304 like this:
let sessionManager: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.requestCachePolicy = .reloadIgnoringCacheData
configuration.timeoutIntervalForRequest = 60
let memoryCapacity = 500 * 1024 * 1024; // 500 MB
let diskCapacity = 500 * 1024 * 1024; // 500 MB
let cache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "shared_cache")
configuration.urlCache = cache
return SessionManager(configuration: configuration)
}()
And
func getData(url:URLConvertible,completionHadler:@escaping(Data?,ErrorMessage?)->Void){
let headers: HTTPHeaders =
[ "Authorization":token!,
"Accept": "application/json",
"if-None-Match": self.loadEtagUserDefault(keyValue: "Etag")
]
self.sessionManager.request(url, method: .get, parameters:nil, headers: headers)
.validate()
.responseJSON { (response) in
switch (response.result) {
case .success:
// SAVE THE RESPONSE INSIDE THE CACHE
self.saveCache(response)
//---
if let unwrappedResponse = response.response {
_ = unwrappedResponse.statusCode
}
// If all went well, I'll return the date
// Recovery Etag from the Header
let etag = response.response?.allHeaderFields["Etag"] as? String
//update in memoria Etag
self.saveEtagUserDefault(etagValue: etag!, key: "Etag")
print("stato codice: \(String(describing: response.response?.statusCode))")
completionHadler(response.data,nil)
break
case .failure(let error):
print(error.localizedDescription)
let statusCode = response.response?.statusCode
let url1:URLRequest? = try! response.request?.asURLRequest()
//Nel caso lo status code è nil perciò il sito non e raggiungibile restituisce la vecchia cache
guard let _ = statusCode else {
let dataOld = self.loadOldDataCache(url: url1!)
completionHadler(dataOld,nil)
return
}
// If the status code is 304 (no change) I return the old cache
if statusCode == 304 {
print("beccato codice 304 ***")
let dataOld = self.loadOldDataCache(url: url1!)
guard let _ = dataOld else {
completionHadler(nil,ErrorMessage.error(description: "data nil"))
return
}
completionHadler(dataOld,nil)
return
}
// *** IN CASE OF ERROR 401 refresh the token and recursively call the same method
print("error - > \n \(error.localizedDescription) \n")
print("stato codice2: \(String(describing: statusCode))")
}
}
}
//Save the response in the cache
private func saveCache(_ response: (DataResponse<Any>)) {
let cachedResponse = CachedURLResponse(response: response.response!, data: response.data!, userInfo: nil, storagePolicy: .allowed)
let mycache:URLCache = self.sessionManager.session.configuration.urlCache!
mycache.storeCachedResponse(cachedResponse, for: response.request!)
}
// Given a Request URL returns the old CACHE in case the site is unresponsive or offline
private func loadOldDataCache(url:URLRequest)->Data?{
let myCache:URLCache = self.sessionManager.session.configuration.urlCache!
let cacheResponse = myCache.cachedResponse(for: url)
return cacheResponse?.data
}
// Except in memory Etag
private func saveEtagUserDefault(etagValue:String,key:String)->Void{
UserDefaults.standard.set(etagValue, forKey:key)
UserDefaults.standard.synchronize()
}
// Recovery from the memory Etag
private func loadEtagUserDefault(keyValue:String)->String{
return UserDefaults.standard.object(forKey: keyValue) as? String ?? "0"
}
}