SDURLCache icon indicating copy to clipboard operation
SDURLCache copied to clipboard

Cache in offline

Open dqueffeulouatw opened this issue 13 years ago • 4 comments

Hi,

This is not a bug but a comment about offline use of SDURLCache.

I'm trying to use SDURLCache to make an offline cache for UIWebView. Actually it doesn't work as in offline I get an error "no connexion available" (no sure about the english message). Code=-1009.

So what I did to solve this problem is to change the cachedResponseForRequest: method to create a new NSCachedURLResponse from the cache instance. This trick works for almost all resources except the JQuery AJAX request because it seems that the statusCode returned is 0. I tried much modifications to make it work but actually I cannot solve this problem : I tried to subclass NSHTTPURLResponse to force statusCode to 0 => statusCode is never called I tried a category on NSURLResponse which implements statusCode => statusCode is called so I can return 200 but jquery still get a 0 status

So I don't know how to control the final response from the cache to the client, mainly the statusCode and the headers.

If you have any information about this, I might be interested.

If you are interested by the changes I made, the code is :

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
    request = [SDURLCache canonicalRequestForRequest:request];

    NSCachedURLResponse *memoryResponse = [super cachedResponseForRequest:request];
    if (memoryResponse)
    {
        if ([self isConnectedToNetwork])
        {
            return memoryResponse;
        }
        else 
        {
            NSURLResponse* response = [[NSURLResponse alloc] initWithURL:request.URL 
                                                            MIMEType:[[memoryResponse response] MIMEType] 
                                               expectedContentLength:[[memoryResponse data] length] 
                                                    textEncodingName:[[memoryResponse response] textEncodingName]];     
            NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:[memoryResponse data] userInfo:nil storagePolicy:NSURLCacheStorageAllowedInMemoryOnly];
            [response release];
            return [cachedResponse autorelease];
        }
    }


    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.
    @synchronized(self.diskCacheInfo)
    {
        NSMutableDictionary *accesses = [self.diskCacheInfo objectForKey:kSDURLCacheInfoAccessesKey];
        if ([accesses objectForKey:cacheKey]) // OPTI: Check for cache-hit in a in-memory dictionnary before to hit the FS
        {
            NSCachedURLResponse *diskResponse = [NSKeyedUnarchiver unarchiveObjectWithFile:[diskCachePath stringByAppendingPathComponent:cacheKey]];
            if (diskResponse)
            {
                // OPTI: Log the 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
                [super storeCachedResponse:diskResponse forRequest:request];

                // SRK: Work around an interesting retainCount bug in CFNetwork on iOS << 3.2.
                if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_2)
                {
                    diskResponse = [super cachedResponseForRequest:request];
                }

                if (diskResponse)
                {
                    if ([self isConnectedToNetwork])
                    {
                        return diskResponse;
                    }
                    else
                    {
                        NSURLResponse* response = [[NSURLResponse alloc] initWithURL:[[diskResponse response] URL] 
                                                                        MIMEType:[[diskResponse response] MIMEType] 
                                                           expectedContentLength:[[diskResponse data] length] 
                                                                textEncodingName:[[diskResponse response] textEncodingName]];
                        NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:[diskResponse data] userInfo:nil storagePolicy:NSURLCacheStorageAllowedInMemoryOnly];

                        [response release];

                        return [cachedResponse autorelease];
                    }
                }
            }
        }
    }
    return nil;
}

dqueffeulouatw avatar Sep 08 '11 15:09 dqueffeulouatw

Hello, thanks for sharing your solution.

I'm trying to do the same but I'm getting error 301 (permanently moved). Am I missing anything?

ale0xb avatar Oct 26 '11 16:10 ale0xb

I don't know. Try first on a page that you're sure it returns 200 anytime.

dqueffeulouatw avatar Oct 27 '11 07:10 dqueffeulouatw

Ok, it was all about the ISS server I'm working with. I can't run any AJAX code though. I'll try to work it out but it doesn't seem to be an easy way of getting it done, I'll open a new thread if I find something.

Cheers

ale0xb avatar Oct 28 '11 12:10 ale0xb

Hi dqueffeulouatw

I'm a little bit late here, but I recently had the same problem as you (I was not using SDURLCache) but the task I tried to solve was the same.

After lots of searching I now found a solution, by implementing my own NSURLProtocol subclass, and not using the cache at all. At least for the injection of the local resources. See http://stackoverflow.com/a/9390792/117959 for more information.

cheers

vkodocha avatar Feb 22 '12 07:02 vkodocha