2015-06-11 4 views
0

Я разрабатываю приложение, которое в значительной степени опирается на AFNetworking для загрузки данных из частного API в модели Mantle. Мой клиент API - это один подкласс класса AFHTTPSessionManager.Блок set by setDataTaskWillCacheResponseBlock на AFHTTPSessionManager никогда не называется

Я пытаюсь реализовать базовый автономный режим, используя NSURLCache. Подход заключается в изменении политики кэширования запроса на dataTaskWithRequest:request:completionHandler до NSURLRequestReturnCacheDataDontLoad, если AFNetworkReachabilityManager говорит, что сеть недоступна.

Хотя я могу проверить, что это фактически работает с использованием контрольных точек во время тестов, сами запросы не кэшируются. Я проверил это, загрузив контейнер приложения из Xcode и проверив файл sqlite Cache.db, который был пуст. Я также проверил, что я смотрю на правильный кеш, вручную создавая манекен NSCachedURLResponse и принудительно сохраняя его в кеше с помощью storeCachedResponse:forRequest. Затем фиктивный ответ появился в файле sqlite Cache.db.

Итак, я думаю, что я сузил проблему, чтобы мои «обычные» ответы не кэшировались. Я также могу изменить заголовки, отправленные API-интерфейсом сервера. То, что я намереваюсь сделать здесь, задает заголовок Cache-Control: private ответов API (чтобы не делать других клиентов, которые используют эти ответы кэша API, они не должны) и изменить этот заголовок кэша в блоке setDataTaskWillCacheResponseBlock, но этот блок никогда не стреляет.

Я понимаю, что система URL может решить, когда звонить URLSession:dataTask:willCacheResponse:completionHandler, который вызывает блок на основе некоторых недокументированных правил, в основном наличие заголовка Cache-Control и отношение размера ответа/размера кеша. Но мой ответ является 145-байт в формате JSON, а заголовок Cache-Control установлен (я проверил как через curl -v и осматривая параметр success блока моей просьбе task.

Я также попытался более агрессивный заголовок кэша, Cache-Control: public, max-age=2592000, чтобы увидеть, если это кэширует ответ или, по меньшей мере, вызывает блок, но поведение было точно так же. Я также проверил myAFHTTPSessionManagerSubclass.session.delegate свойство, которое действительно указывал на myAFHTTPSessionManagerSubclass, как и ожидалось.

Я также попытался перекрывая URLSession:dataTask:willCacheResponse:completionHandler непосредственно в мой подкласс, но он все еще не был вызван. Установка точки останова на этом же методе делегата на AFURLSessionManager.m в th e Pods также не работает, выполнение никогда не останавливается на контрольной точке.

Я использую версию 2.5.4 AFNetworking, согласно моему файлу Podfile.lock.

Итак, как сделать кеш ответов (желательно без установки агрессивных политик кэширования в ответ), поэтому я могу реализовать быстрый автономный режим в своем приложении?

EDIT: Я также попытался создать 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)

ответ

2

Ну, я удивлю вас - код, который вы написали выше, работает просто отлично ... но это неправильно за то, что вы пытаетесь для достижения;)

Причина просто - методы делегирования не вызывается при создании запросов по методу dataTaskWithRequest:completionHandler:. Вместо этого вам нужно использовать метод dataTaskWithRequest:.

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW1 - читать первый Note

Вторая вещь в том, что NSURLSession просто очень ек, когда мы говорим о кэшировании. Вы можете столкнуться с несколькими проблемами в iOS 7.x/8.x. Я столкнулся с таким кошмаром, когда я использовал пользовательский кеш в своем приложении, что в итоге не имеет ничего общего с NSURLCache. Также я решил создать свою структуру, основанную на NSURLSession и AFNetworking.

Одной из проблем на iOS 7 является создание NSURLSession с defaultConfiguration, объект NSURLCache будет отличаться от глобального - совершенно неожиданное поведение. Одна из проблем на 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 :)

Смежные вопросы