Skip to content

Instantly share code, notes, and snippets.

@kevindelord
Last active August 10, 2023 13:58
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kevindelord/35a0a098fbcabfb92259 to your computer and use it in GitHub Desktop.
Save kevindelord/35a0a098fbcabfb92259 to your computer and use it in GitHub Desktop.
How to integrate Etag in Swift
let API_HEADER_FIELD_NONE_MATCH : String = "If-None-Match"
let API_HEADER_FIELD_ETAG : String = "Etag"
let API_REQUEST_SUCCESS : Int = 200
func ETagForURL(urlString: String) -> String? {
// return the saved ETag value for the given URL
return NSUserDefaults.standardUserDefaults().objectForKey(urlString) as String?
}
func updateETag(urlResponse: NSURLResponse!) {
if let httpResponse = urlResponse as? NSHTTPURLResponse {
if let urlString = httpResponse.URL?.absoluteString {
if let etag = httpResponse.allHeaderFields[API_HEADER_FIELD_ETAG] as? String {
// save the etag header value with the url as a key.
NSUserDefaults.standardUserDefaults().setObject(etag, forKey: urlString)
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
}
func readFromBackend() {
let urlString = "https://herderbeten.s3.eu-central-1.amazonaws.com/impressum/imprint.html"
// create a mutable request
var request = NSMutableURLRequest(URL: NSURL(string: urlString)!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 60);
// add etag header value
if let etag = self.ETagForURL(urlString) {
request.addValue(etag, forHTTPHeaderField: API_HEADER_FIELD_NONE_MATCH)
}
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if (error != nil) {
UIAlertView(title: L("API_ERROR"), message: error.localizedDescription, delegate: nil, cancelButtonTitle: nil, otherButtonTitles:"ok").show()
}
if (response != nil) {
self.updateETag(response)
if let httpResponse = response as? NSHTTPURLResponse {
// Only update the entities if the status code is K_API_REQUEST_SUCCESS (200) and if there is no ERROR
// The status code could also be K_API_REQUEST_CACHED (304) depending on the etag status
if (httpResponse.statusCode == API_REQUEST_SUCCESS && error == nil && data != nil) {
// New data fetched
let htmlText = NSString(data: data, encoding: NSUTF8StringEncoding)
return
}
}
}
// An error occured OR nothing changed. The application should use cached data.
}
}
// MARK: - Write files to cache folder
func writeDataToFile(data: NSData, filename: String) {
if let path = self.getCacheDirectoryFilepath(filename) {
data.writeToFile(path, atomically: false)
self.addSkipBackupAttributeToItemAtURL(NSURL.fileURLWithPath(path as NSString))
}
}
func getCacheDirectoryFilepath(filename: String) -> String? {
let directories : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if let cacheFolderPath = directories?.first {
return cacheFolderPath.stringByAppendingPathComponent(filename)
}
return nil
}
func addSkipBackupAttributeToItemAtURL(URL: NSURL!) -> Bool {
assert(NSFileManager.defaultManager().fileExistsAtPath(URL.path!))
var error : NSError? = nil
var success : Bool = URL.setResourceValue(true, forKey: NSURLIsExcludedFromBackupKey, error: &error)
if (success == false || error != nil) {
println("Error excluding \(URL.lastPathComponent) from backup \(error) ")
}
return success
}
@moosabaloch
Copy link

@kevindelord why do you need to do this all stuff when NSURLRequest.CachePolicy.useProtocolCachePolicy provides all sorts of implementation by default based on RFC 2616.

https://developer.apple.com/documentation/foundation/nsurlrequest/cachepolicy/useprotocolcachepolicy
https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13

@ulitiy
Copy link

ulitiy commented Aug 10, 2023

Probably because cache could be lost but you could have a copy of some file locally that you don't need to update so you don't get too much traffic on your hosting. That's my case at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment