我正在使用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,根据苹果文档,它的工作方式如下:



因此,只要缓存不陈旧,即使在飞行模式下,一切都可以完美运行。当高速缓存到期时(最大使用期限和其他时间),将调用故障块。

我在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

最佳答案

好吧,我终于找到了一个不太丑陋的解决方法:

第一

如果您使用的是IOS5/IOS6,则可以删除SDURLCache并使用 native 的:

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

但是请记住,在IOS5中,https请求不会被缓存在IOS6中。

第二

我们需要在Prefix.pch中添加以下框架,以便AFNetworking可以开始监视我们的Internet连接。
#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响应中设置正确的缓存头。

  • 更新

    看起来IOS6在无Internet的情况下加载缓存的响应时遇到一些问题,因此即使请求被缓存并且请求缓存策略设置为NSURLRequestReturnCacheDataDontLoad,请求也将失败。

    因此,一个丑陋的解决方法是修改(void)connection:(NSURLConnection __unused *)connection didFailWithError:(NSError *)error中的AFURLConnectionOperation.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;
            }
        }
    }
    

    关于iphone - 带有AFNetworking和脱机模式的SDURLCache不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10250055/

    10-13 04:03