NSURLProtocol не запрашивается для загрузки после ответа YES на canInitWithRequest
Я регистрирую реализацию NSURLProtocol для некоторой пользовательской обработки определенных запросов URL (я отмечаю эти запросы, устанавливая свойства для них). Эти URL-запросы поступают из метода загрузки UIWebView.
- Создать веб-представление пользовательского интерфейса (первая загрузка после запуска)
- Загрузить контент
- Уничтожить веб-просмотр
- Создать новый веб-вид (последующие загрузки)
- Загрузить контент
Я наблюдаю существенно различное поведение между шагами 2 и 5. Моя реализация NSURLProtocol управляет кэшированными данными и предназначена для обработки запросов. Если я не обнаруживаю свою собственность в запросе, я делаю вторую проверку для определенного URL (для отладки). В любом случае canInitWithRequest
вернусь YES
:
Первая загрузка после запуска:
2014-10-15 11:37:11.403 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ebbb40> https://example.com/
2014-10-15 11:37:11.404 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15dc8da0> https://example.com/
2014-10-15 11:37:11.409 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee5ef0> https://example.com/
2014-10-15 11:37:11.409 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee6240> https://example.com/
2014-10-15 11:37:11.410 MYApp[5813:60b] MYURLProtocol initWithRequest:cachedResponse:client: Request: https://example.com/
2014-10-15 11:37:11.411 MYApp[5813:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x15ee69d0> https://example.com/
2014-10-15 11:37:11.415 MYApp[5813:9c07] MYURLProtocol startLoading Loading <0x15ee6240> https://example.com/
... A bunch of loading of assets occurs (cached responses) ...
2014-10-15 11:37:12.497 MYApp[5813:60b] MyWebViewController webViewDidFinishLoad: Finished loading
Другие отметили, что к протоколу обращаются несколько раз об одном и том же активе, и это не проблема, хотя интересно отметить, что каждый раз, когда он вызывается с новым объектом, это 4-й (из 4-х) объект который передается startLoading
, Тем не менее, никаких реальных проблем здесь.
Последующие нагрузки:
2014-10-15 11:11:27.466 MYApp[5782:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x1727c310> https://example.com/
2014-10-15 11:11:27.467 MYApp[5782:60b] MYURLProtocol canInitWithRequest: Matched property in request: <0x145b1d90> https://example.com/
2014-10-15 11:11:27.488 MYApp[5782:560f] MYURLProtocol canInitWithRequest: Matched URL in request: <0x17266060> https://example.com/
2014-10-15 11:11:27.669 MYApp[5782:60b] MYWebViewController webViewDidFinishLoad: Finished loading
Вот где поведение, на мой взгляд, неожиданно. Похоже, что свойство было удалено из запроса в третий раз, когда оно передается canInitWithRequest
и затем, даже если мы отвечаем YES
мы никогда не получим инициацию - страница просто возвращается UIWebView
в целом, без последующих запросов на активы. Вот как выглядит запрос при его создании:
NSURLRequest *request = [NSURLRequest requestWithURL:myURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[self.webView loadRequest:request];
Почему, когда я говорю, что мой протокол может обработать запрос, ему не предоставляется такая возможность? Я предполагаю, что ответ заключается в реализации самого UIWebView. Любые мысли о том, как обойти это, если я действительно хочу, чтобы мой протокол был ответственным за загрузку?
2 ответа
Мне удалось обойти эту проблему, удалив кэш-память UIWebView, но не удаляя NSURLCache.
- Добавьте уникальный параметр в параметры запроса исходного запроса. Я выбрал "ключ =000000", где значением является шестизначное случайное число с нулевым светодиодом.
- В протоколе раздень ключ
canonicalRequestForRequest:
И вinitWithRequest:cachedResponse:client
Мой код для удаления выглядит следующим образом (может быть более чистый способ удаления параметров, но это работает):
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
NSURLRequest *canonicalRequest = request;
BOOL myProtocolRequest = [[NSURLProtocol propertyForKey:kMYProtocolRequest inRequest:request] boolValue];
if (myProtocolRequest)
{
NSMutableURLRequest *mutableRequest = [request mutableCopyWorkaround];
NSString *originalURLString = mutableRequest.URL.absoluteString;
NSString *regexString = [NSString stringWithFormat:@"(?:[?&])(key=[[:digit:]]{%d}&*)", kMYKeyLength];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:0 error:0];
NSTextCheckingResult *result = [regex firstMatchInString:originalURLString options:0 range:NSMakeRange(0, originalURLString.length)];
if (result.numberOfRanges > 1)
{
NSRange keyRange = [result rangeAtIndex:1];
NSLog(@"Removing '%@' from request", [originalURLString substringWithRange:keyRange]);
NSString *replacementURLString = [originalURLString stringByReplacingCharactersInRange:keyRange withString:@""];
mutableRequest.URL = [NSURL URLWithString:replacementURLString];
canonicalRequest = mutableRequest;
}
}
return canonicalRequest;
}
Мой код инициализации выглядит так:
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client
{
self = [super initWithRequest:[MYURLProtocol canonicalRequestForRequest:request] cachedResponse:cachedResponse client:client];
return self;
}
Мне не нравится, что я должен это делать, но я наконец получаю именно то поведение, которое хочу. Надеюсь, это поможет кому-то там.
*** Way to clear the cache of webview **********
Follow this code:
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
[[NSUserDefaults standardUserDefaults] synchronize];