永远不会调用AFHTTPSessionManager上由setDataTaskWillCacheResponseBlock设置的块

时间:2015-06-11 13:01:19

标签: objective-c caching afnetworking

我开发了一个依赖于AFNetworking的应用程序,可以将数据从私有API加载到Mantle模型中。我的API客户端是AFHTTPSessionManager的单例子类。

我正试图通过利用NSURLCache来实现基本的离线模式。如果dataTaskWithRequest:request:completionHandler表示无法访问网络,则方法是将NSURLRequestReturnCacheDataDontLoad上的请求缓存策略修改为AFNetworkReachabilityManager

虽然我可以通过在测试期间使用断点来验证这实际上是有效的,但是请求本身并未被缓存。我通过从Xcode下载应用程序容器并检查Cache.db sqlite文件来验证这一点,该文件是空的。我还通过手动创建虚拟NSCachedURLResponse并使用storeCachedResponse:forRequest强制将其存储在缓存中来验证我正在查看正确的缓存。然后虚拟响应确实显示在Cache.db sqlite文件中。

所以,我认为我将问题缩小到我的“通常”响应,而不是缓存。我还可以修改服务器API发送的标头。我打算在这里做的是在API响应上设置标头Cache-Control: private(以便不使其他客户端使用它不应该使用此API缓存响应),并在{}块中修改此缓存标头{1}},但这个区块永远不会发射。

据我所知,URL系统可能会根据一些未记录的规则,主要是setDataTaskWillCacheResponseBlock标头的存在以及响应大小/缓存大小来决定何时调用URLSession:dataTask:willCacheResponse:completionHandler来调用该块比。但我的响应是一个145字节的JSON,Cache-Control标头已设置(我通过Cache-Control验证并检查我的请求的curl -v块的task参数。

我还尝试了一个更积极的缓存标头success,以查看是否缓存了响应或至少调用了块,但行为完全相同。我还按预期检查了Cache-Control: public, max-age=2592000属性,该属性确实指向myAFHTTPSessionManagerSubclass.session.delegate

我也尝试直接在我的子类中覆盖myAFHTTPSessionManagerSubclass,但它仍未被调用。在URLSession:dataTask:willCacheResponse:completionHandler目录中AFURLSessionManager.m上的同一委托方法上设置断点也不起作用,执行永远不会在断点处停止。

根据我的Pods文件,我正在使用AFNetworking的2.5.4版。

那么,如何让我的回复缓存(最好不要在响应上设置激进的缓存策略),这样我就可以在我的应用中实现快速离线模式?

编辑:我还尝试创建Podfile.lock以查看是否可行。所以,我创建了一个简单的Node.js服务器,它只是回答一些简单的事情并设置一个缓存头:

NSURLSession

然后创建了一个简单的视图控制器来测试:

$ curl -v http://192.168.1.107:1337/
* Hostname was NOT found in DNS cache
*   Trying 192.168.1.107...
* Connected to 192.168.1.107 (192.168.1.107) port 1337 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 192.168.1.107:1337
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Cache-Control: public
< Date: Thu, 11 Jun 2015 14:38:14 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
Hello World

正确打印了响应,但永远不会调用- (void)viewDidLoad { [super viewDidLoad]; // Prime the cache [NSURLCache setSharedURLCache:[[NSURLCache alloc] initWithMemoryCapacity:2*1024 diskCapacity:10*1024*1024 diskPath:@"mytestcache"]]; // The sleep is to be absolutely sure the cache did initialise sleep(2); NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; [[session dataTaskWithURL:[NSURL URLWithString:@"http://192.168.1.107:1337"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"Got response: %@", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]); }] resume]; } -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *))completionHandler { completionHandler(proposedResponse); } (我设置了一个断点)。我再次尝试检查容器,并创建了willCacheResponse目录,但它是空的。我也尝试了mytestcache,得到了相同的结果。

(在https://github.com/AFNetworking/AFNetworking/issues/2780交叉发布到AFNetworking问题)

1 个答案:

答案 0 :(得分:2)

好吧,我会让你大吃一惊 - 你上面写的代码工作得很好,但是对于你想要实现的目标它是不正确的;)

原因很简单 - 当您通过方法dataTaskWithRequest:completionHandler:创建请求时,不会调用委托方法。您需要使用方法dataTaskWithRequest:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW1 - 首先阅读注意

第二件事是,当我们讨论缓存时,NSURLSession真的是sux。您可能在iOS 7.x / 8.x中遇到了几个问题。当我在我的应用程序中实现自定义缓存时,我遇到了这样的噩梦,最终与NSURLCache没有任何共同之处。我还决定基于NSURLSession和AFNetworking创建我的框架。

iOS 7上的一个问题是使用NSURLSession创建defaultConfigurationNSURLCache对象与全局对象不同 - 非常意外的行为。 iOS 8的一个问题是POST请求也被缓存,这可能会危及应用程序的安全性。 BTW https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=nsurlcache+ios+8+broken

也许它没有回答你的问题,但你应该知道iOS版本之间的奇怪行为和差异。 老实说,我建议您使用AFHTTPRequestOperationManager而不是AFHTTPSessionManager,因为至少NSURLConnection的工作方式与NSURLCache有害:)