SDURLCache与AFNetworking和离线模式不工作(SDURLCache with AF

2019-06-23 19:29发布

我使用AFNetworkingSDURLCache我所有的网络操作。

我有SDURLCache设置是这样的:

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];

我所有的要求正在使用的CachePolicy NSURLRequestUseProtocolCachePolicy ,根据苹果的文档,其工作原理是这样的:

如果NSCachedURLResponse不会为请求存在,则该数据是从始发源获取。 如果是请求缓存响应,网址加载系统进行检查,以确定它是否指定的内容必须重新验证响应。 如果内容必须进行重新验证的连接到原始源,看它是否已经改变。 如果没有改变,那么响应是从本地缓存返回。 如果它的变化,该数据是从原始来源获取。

如果缓存响应不指定的内容必须重新验证,在响应中规定的最大年龄或过期检查。 如果缓存响应是足够新,则响应从本地缓存返回。 如果响应被确定为过时,始发源被检查较新的数据。 如果新的数据可用,数据是从原始来源获取,否则它从缓存中返回。

所以,一切只要缓存不陈旧完美的作品,即使在飞行模式。 当缓存过期(最大年龄等),故障块被调用。

我已经挖了一点内部SDURLCache和此方法返回的有效数据的响应(我已经分析的数据为字符串,它包含缓存信息)

- (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
            objectForKey:kAFURLCacheInfoAccessesKey];
        // 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;
}

所以在这一点上,我不知道做什么,因为我相信,响应由操作系统来处理,然后AFNetworking接收

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

里面AFURLConnectionOperation

Answer 1:

嗯,我终于达到了一个不那么难看的解决方法:

第一

如果您使用的IOS5 / iOS6的,你可以删除SDURLCache并使用本机之一:

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

但要记住的是,在iOS6的他们会不会被缓存IOS5 HTTPS请求。

第二

我们需要以下框架添加到我们的Prefix.pch所以AFNetworking可以开始监视我们的互联网连接。

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

第三

我们需要和AFHTTPClient实例,所以我们可以截取每个传出的请求,并改变了他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;
}

有了这些代码撕成小块当WiFi / 3G是不可用,并且指定要始终使用缓存无论什么要求,我们现在可以探测到。 (离线模式)

笔记

  • 我还是不知道该怎么办时, networkReachabilityStatusAFNetworkReachabilityStatusUnknown发生这种情况是申请尽快作出在应用程序启动和AF未取得互联网状态呢。

  • 请记住,为了这个工作的服务器设置正确的缓存头在HTTP响应。

UPDATE

看起来iOS6的有一些问题加载缓存的响应在没有互联网的情况,所以即使请求被高速缓存,并请求缓存策略seted到NSURLRequestReturnCacheDataDontLoad请求将失败。

因此,一个丑陋的解决方法是修改(void)connection:(NSURLConnection __unused *)connection didFailWithError:(NSError *)errorAFURLConnectionOperation.m如果请求失败,但只对特定的高速缓存策略检索缓存的响应。

- (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 (cachedResponse.data.length > 0) {
            self.responseData = cachedResponse.data;
            self.response = cachedResponse.response;
            self.error = nil;
        }
    }
}


Answer 2:

没有你的HTTP头不能告诉太多-但这样做的最常见的原因是NSURLProtocol迫使重新验证提供缓存响应的WebView之前。

请看看这里: http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588



Answer 3:

这听起来好像要请求成功,即使高速缓存表示,数据已经过期,应该从服务器中检索。 你可能有一些运气设定一定的要求 ,你宁愿使用比失败陈旧数据的缓存策略(在线与脱机不同的政策)。

NSMutableURLRequest - > setCachePolicy

它看起来像NSURLRequestReturnCacheDataDontLoad是离线模式所需的策略。

希望帮助!



文章来源: SDURLCache with AFNetworking and offline mode not working