SDURLCache with AFNetworking and offline mode not working

I’m using AFNetworking and SDURLCache for all my networking operations.

I have SDURLCache set like this:

  • Xcode: ld: library not found for -lAFNetworking
  • App crash when trying to load a large amount off data into my app
  • How to simulate HTTP form (POST) submit on iOS
  • afnetworking 3.0 Migration: how to POST with headers and HTTP Body
  • iOS Cache Policy
  • iOS Cache a UIWebView
  • SDURLCache *urlCache = [[SDURLCache alloc]
            initWithMemoryCapacity:1024*1024*2   // 2MB mem cache
            diskCapacity:1024*1024*15 // 15MB disk cache
            diskPath:[SDURLCache defaultCachePath]];
        [urlCache setMinCacheInterval:1];
        [NSURLCache setSharedURLCache:urlCache];

    All my request are using cachePolicy NSURLRequestUseProtocolCachePolicy, which according to apple docs works like this:

    If an NSCachedURLResponse does not exist for the request, then the
    data is fetched from the originating source. If there is a cached
    response for the request, the URL loading system checks the response
    to determine if it specifies that the contents must be revalidated. If
    the contents must be revalidated a connection is made to the
    originating source to see if it has changed. If it has not changed,
    then the response is returned from the local cache. If it has changed,
    the data is fetched from the originating source.

    If the cached response doesn’t specify that the contents must be revalidated, the maximum age or expiration specified in the response
    is examined. If the cached response is recent enough, then the
    response is returned from the local cache. If the response is
    determined to be stale, the originating source is checked for newer
    data. If newer data is available, the data is fetched from the
    originating source, otherwise it is returned from the cache.

    So everything works perfectly even in airplane mode as long as the cache is not stale. When the cache expires (max-age and others), the failure block gets called.

    I’ve been digging a little inside the SDURLCache and this method returns a response with valid data (I’ve parsed the data to a string and it contains the cached information)

    - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
        request = [SDURLCache canonicalRequestForRequest:request];
        NSCachedURLResponse *memoryResponse =
            [super cachedResponseForRequest:request];
        if (memoryResponse) {
            return memoryResponse;
        NSString *cacheKey = [SDURLCache cacheKeyForURL:request.URL];
        // NOTE: We don't handle expiration here as even staled cache data is
        // necessary for NSURLConnection to handle cache revalidation.
        // Staled cache data is also needed for cachePolicies which force the
        // use of the cache.
        __block NSCachedURLResponse *response = nil;
        dispatch_sync(get_disk_cache_queue(), ^{
            NSMutableDictionary *accesses = [self.diskCacheInfo
            // OPTI: Check for cache-hit in in-memory dictionary before to hit FS
            if ([accesses objectForKey:cacheKey]) {
                response = [NSKeyedUnarchiver unarchiveObjectWithFile:
                    [_diskCachePath stringByAppendingPathComponent:cacheKey]];
                if (response) {
                    // OPTI: Log entry last access time for LRU cache eviction
                    // algorithm but don't save the dictionary
                    // on disk now in order to save IO and time
                    [accesses setObject:[NSDate date] forKey:cacheKey];
                    _diskCacheInfoDirty = YES;
        // OPTI: Store the response to memory cache for potential future requests
        if (response) {
            [super storeCachedResponse:response forRequest:request];
        return response;

    So at this point I have no idea what to do, because I believe that the response is handled by the OS and then AFNetworking receives a

    - (void)connection:(NSURLConnection *)__unused connection 
      didFailWithError:(NSError *)error

    inside AFURLConnectionOperation.

    3 Solutions Collect From Internet About “SDURLCache with AFNetworking and offline mode not working”

    Well I’ve finally reached a not so ugly workaround:


    If you’re using IOS5/IOS6 you can drop SDURLCache and use the native one:

    //Set Cache
    NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
                                                         diskCapacity:20 * 1024 * 1024
    [NSURLCache setSharedURLCache:URLCache];

    But remember that in IOS5 https requests wont be cached in IOS6 they will.


    We need to add the following frameworks to our Prefix.pch so AFNetworking can start monitoring our internet connection.

    #import <MobileCoreServices/MobileCoreServices.h>
    #import <SystemConfiguration/SystemConfiguration.h>


    We need and AFHTTPClient instance so we can intercept every outgoing request and change his cachePolicy

    -(NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters {
        NSMutableURLRequest * request = [super requestWithMethod:method path:path parameters:parameters];
        if (request.cachePolicy == NSURLRequestUseProtocolCachePolicy && self.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
            request.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
        if (self.networkReachabilityStatus == AFNetworkReachabilityStatusUnknown) {
            puts("uknown reachability status");
        return request;

    With these peaces of code we can now detect when the wifi/3g is unavailable and the specify the request to use always the cache no matter what. (Offline Mode)


    • I still don’t know what to do when the networkReachabilityStatus is AFNetworkReachabilityStatusUnknown This can happen is a request is made as soon as the application starts and AF has not obtained the internet status yet.

    • Remember that in order for this to work the server has to set the correct cache headers in the http response.


    Looks like IOS6 has some problems loading cached responses in no-internet situations, so even if the request is cached and the request cache policy is seted to NSURLRequestReturnCacheDataDontLoad the request will fail.

    So an ugly workaround is to modify (void)connection:(NSURLConnection __unused *)connection
    didFailWithError:(NSError *)error
    in AFURLConnectionOperation.m to retrieve the cached response if the request fails but only for specific cache policies.

    - (void)connection:(NSURLConnection __unused *)connection
      didFailWithError:(NSError *)error
        self.error = error;
        [self.outputStream close];
        [self finish];
        self.connection = nil;
        //Ugly hack for making the request succeed if we can find a valid non-empty cached request
        //This is because IOS6 is not handling cache responses right when we are in a no-connection sittuation
        //Only use this code for cache policies that are supposed to listen to cache regarding it's expiration date
        if (self.request.cachePolicy == NSURLRequestUseProtocolCachePolicy ||
            self.request.cachePolicy == NSURLRequestReturnCacheDataElseLoad ||
            self.request.cachePolicy == NSURLRequestReturnCacheDataDontLoad) {
            NSCachedURLResponse * cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
            if ( > 0) {
                self.responseData =;
                self.response = cachedResponse.response;
                self.error = nil;

    Can’t tell much without your HTTP headers — but the most common reason for this is NSURLProtocol forcing revalidation before delivering cached response to WebView.

    Please take a look here :

    It sounds like you want the request to succeed, even though the cache says the data has expired and should be retrieved from the server. You may have some luck setting the cache policy (different policy for online vs. offline) of certain requests where you’d rather use stale data than fail.

    NSMutableURLRequest -> setCachePolicy

    It looks like NSURLRequestReturnCacheDataDontLoad is the policy you want for offline mode.

    Hope that helps!