【发布时间】:2015-06-11 13:01:19
【问题描述】:
我开发了一个应用程序,它严重依赖 AFNetworking 将数据从私有 API 加载到 Mantle 模型中。我的 API 客户端是 AFHTTPSessionManager 的单例子类。
我正在尝试通过利用NSURLCache 来实现基本的离线模式。方法是如果AFNetworkReachabilityManager表示网络不可达,则将dataTaskWithRequest:request:completionHandler上的请求缓存策略修改为NSURLRequestReturnCacheDataDontLoad。
虽然我可以通过在测试期间使用断点来验证这确实有效,但请求本身并没有被缓存。我通过从 Xcode 下载应用程序容器并检查 Cache.db sqlite 文件来验证这一点,该文件是空的。我还通过手动创建一个虚拟NSCachedURLResponse 并使用storeCachedResponse:forRequest 将其强制存储在缓存中来验证我正在查看正确的缓存。然后虚拟响应确实出现在 Cache.db sqlite 文件中。
所以,我认为我将问题缩小到我的“通常”响应没有被缓存。我还可以修改服务器 API 发送的标头。我打算在这里做的是在 API 响应上设置一个标头 Cache-Control: private(以免使其他使用此 API 缓存响应的客户端不应该使用),并在 setDataTaskWillCacheResponseBlock 块中修改此缓存标头,但这个块永远不会触发。
我了解 URL 系统可能会根据一些未记录的规则(主要是 Cache-Control 标头的存在以及响应大小/缓存大小比率)来决定何时调用调用块的 URLSession:dataTask:willCacheResponse:completionHandler。但是我的响应是一个 145 字节的 JSON,并且设置了 Cache-Control 标头(我通过 curl -v 验证并检查了我的请求的 success 块的 task 参数。
我还尝试了更激进的缓存标头Cache-Control: public, max-age=2592000,以查看它是否缓存响应或至少调用块,但行为完全相同。我还检查了myAFHTTPSessionManagerSubclass.session.delegate 属性,正如预期的那样,它确实指向myAFHTTPSessionManagerSubclass。
我也尝试在我的子类中直接覆盖URLSession:dataTask:willCacheResponse:completionHandler,但它仍然没有被调用。在 Pods 目录中的 AFURLSessionManager.m 上的同一委托方法上设置断点也不起作用,执行永远不会在断点处停止。
根据我的Podfile.lock 文件,我使用的是 AFNetworking 2.5.4 版。
那么,如何让我的响应缓存(最好不要对响应设置积极的缓存策略),以便我可以在我的应用中实现快速离线模式?
编辑:我还尝试创建一个NSURLSession 看看这是否可行。所以,我创建了一个简单的 Node.js 服务器,它只回答一些简单的问题并设置一个缓存头:
$ 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 目录,但它是空的。我也试过Cache-Control: max-age=86400,得到同样的结果。
(交叉发布到 AFNetworking 问题:https://github.com/AFNetworking/AFNetworking/issues/2780)
【问题讨论】:
标签: objective-c caching afnetworking