Nsurlcache and Etags

NSURLCache and ETags

yes it does handle it transparently if you set its cache mode:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy: NSURLRequestUseProtocolCachePolicy

note: you cannot see the header in the request at all and if a 304 response is returned by the server you will only see the 200 response that it transparently loaded from the cache.

How to clear cached response and ETag info when using NSURLCache?

This is an HTTP protocol thing, not a RestKit thing, so you need to look at the underlying handling / storage. So, I would expect your code to work. I don't think AFNetworking creates its own cache instance, but it might - it's worth checking in the code.

You could create the NSURLRequest to send using RestKit and then set the cachePolicy to NSURLRequestReloadIgnoringLocalAndRemoteCacheData.

How to use NSURLSession to determine if resource has changed?

I created a HTTPEntityFingerprint structure which stores some of the entity headers: Content-MD5, Etag, and Last-Modified.

import Foundation

struct HTTPEntityFingerprint {
let contentMD5 : String?
let etag : String?
let lastModified : String?

extension HTTPEntityFingerprint {
init?(response : NSURLResponse) {
if let httpResponse = response as? NSHTTPURLResponse {
let h = httpResponse.allHeaderFields
contentMD5 = h["Content-MD5"] as? String
etag = h["Etag"] as? String
lastModified = h["Last-Modified"] as? String

if contentMD5 == nil && etag == nil && lastModified == nil {
return nil
} else {
return nil

static func match(first : HTTPEntityFingerprint?, second : HTTPEntityFingerprint?) -> Bool {
if let a = first, b = second {
if let md5A = a.contentMD5, md5B = b.contentMD5 {
return md5A == md5B
if let etagA = a.etag, etagB = b.etag {
return etagA == etagB
if let lastA = a.lastModified, lastB = b.lastModified {
return lastA == lastB

return false

When I get an NSHTTPURLResponse from an NSURLSession, I create an HTTPEntityFingerprint from it and compare it against a previously stored fingerprint using HTTPEntityFingerprint.match. If the fingerprints match, then the HTTP resource hasn't changed and thus I do not need to deserialized the JSON response again; however, if the fingerprints do not match, then I deserialize the JSON response and save the new fingerprint.

This mechanism only works if your server returns at least one of the 3 entity headers: Content-MD5, Etag, or Last-Modified.

More Details on NSURLSession and NSURLCache Behavior

The caching provided by NSURLSession via NSURLCache is transparent, meaning when you request a previously cached resource NSURLSession will call the completion handlers/delegates as if a 200 response occurred.

If the cached response has expired then NSURLSession will send a new request to the origin server, but will include the If-Modified-Since and If-None-Match headers using the Last-Modified and Etag entity headers in the cached (though expired) result; this behavior is built in, you don't have to do anything besides enable caching. If the origin server returns a 304 (Not Modified), then NSURLSession will transform this to a 200 response the application (making it look like you fetched a new copy of the resource, even though it was still served from the cache).

eTag support using Alamofire 4

By default, caching is ON. If you log HTTP traffic inside your app, you might see cached responses, without the app making requests to server this time.

In case when URLSession decides to return cached response instead of going to server you will see same Date HTTP response header.

To ensure caching is working, you should inspect network packets between your app and server.

Related Topics

Leave a reply