且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

具有AFNetworking和离线模式的SDURLCache无法正常工作

更新时间:2022-05-14 01:35:18

好吧我终于达不到了如此丑陋的解决方法:

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

第一次

如果你正在使用IOS5 / IOS6您可以删除SDURLCache并使用原生的:

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
                                                         diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

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

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

第二

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

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>

第三

我们需要和AFHTTPClient实例,所以我们可以拦截每个传出请求并更改他的 cachePolicy

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

凭借这些代码和平,我们现在可以检测到wifi / 3g何时不可用并指定始终使用缓存的请求,无论如何。 (离线模式)

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)

注释


  • networkReachabilityStatus AFNetworkReachabilityStatusUnknown 时,我仍然不知道该怎么办这可能发生请求一旦应用程序启动并且AF尚未获得互联网状态。

  • 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.

请记住,为了使其正常工作,服务器必须设置正确的缓存http响应中的标题。

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

更新

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

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.

所以一个丑陋的解决方法是修改(void)连接:(NSURLConnection __unused *)connection
didFailWithError: (NSError *)错误
AFURLConnectionOperation.m 中检索缓存响应,如果请求失败但仅针对特定缓存策略。

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