Кэширование не работает с пользовательским NSURLProtocol

Я пытаюсь создать подкласс NSURLProtocol. Однако я замечаю, что теряю функциональность кэширования, когда регистрирую свой подкласс, хотя он ничего не должен делать. Например, если я выполняю [NSURLConnection sendSynchronousRequest...] несколько раз для одного и того же URL-адреса без регистрации подкласса, он выполняет только один фактический HTTP-запрос. Когда этот подкласс зарегистрирован, он каждый раз выполняет сетевой запрос.

Вот мой код:

@interface CustomURLProtocol : NSURLProtocol
@property (nonatomic, strong) NSURLConnection *connection;
@end

@implementation CustomURLProtocol

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    return [[[request URL] scheme] isEqualToString:@"http"] &&
           [NSURLProtocol propertyForKey:@"tagged" inRequest:request] == nil;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

- (void)startLoading {
    NSMutableURLRequest *newRequest = [self.request mutableCopy];
    [NSURLProtocol setProperty:@YES forKey:@"tagged" inRequest:newRequest];
    self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}

- (void)stopLoading {
    [self.connection cancel];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [[self client] URLProtocol:self didLoadData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [[self client] URLProtocol:self didFailWithError:error];
    self.connection = nil;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[[self request] cachePolicy]];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection  {
    [[self client] URLProtocolDidFinishLoading:self];
    self.connection = nil;
}
@end

person ahb    schedule 28.09.2013    source источник


Ответы (2)


Проблема здесь была не в том, что я ожидал. Настоящая проблема заключалась в том, что перенаправления не обрабатывались правильно, поскольку не было следующего кода:

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response {
  [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
  return request;
}

Без этого кода перенаправления не кэшировались, поэтому запросы, поэтому последовательные запросы к перенаправленному URL-адресу, такому как wikipedia.com, приводили к перенаправлению каждый раз.

person ahb    schedule 30.09.2013

Я думаю, что добавленная вами строка предназначена только для пропуска вашего пользовательского NSURLProtocol. После добавления этого метода эти методы connectionDelegate все еще вызываются?

Обновление: наконец-то понял это. Это причина. Я заставил это работать после добавления этой части в startLoading.

NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
    if (cachedResponse) {  
        [self connection:nil didReceiveResponse:[cachedResponse response]];
        [self connection:nil didReceiveData:[cachedResponse data]];
        [self connectionDidFinishLoading:nil];
    } else {
        _connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
    }
person jqyao    schedule 04.06.2014
comment
Я думаю, возможная причина в том, что пользовательский NSURLProtocol вообще не рассматривается как http. Тогда политика кэширования, отправленная запросом, по умолчанию является NSURLRequestUseProtocolCachePolicy, и система загрузки URL-адресов не знает, как ее кэшировать, поэтому она просто удаляет их все. - person jqyao; 05.06.2014