我已经写了一个NSURLProtocol,它将针对URL的http到本地路径映射检查出站plist请求,并提供本地内容,然后使用NSURLCache:对其进行缓存

- (void)startLoading
{
    //Could this be why my responses never come out of the cache?
    NSURLResponse *response =[[NSURLResponse alloc]initWithURL:self.request.URL
                                                      MIMEType:nil expectedContentLength:-1
                                              textEncodingName:nil];

    //Get the locally stored data for this request
    NSData* data = [[ELALocalPathSubstitutionService singleton] getLocallyStoredDataForRequest:self.request];

    //Tell the connection to cache the response
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];

    //Have the connection load the data we just fetched
    [[self client] URLProtocol:self didLoadData:data];

    //Tell the connection to finish up
    [[self client] URLProtocolDidFinishLoading:self];
}

我限制了可以提取本地数据的次数。目的是,第一次获取它的意图将来自NSBundle,但是此后,它将使用库存的NSURLCache来检查它是否应来自缓存网络:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    //Check if we have pre-loaded data for that request
    ELAPathSubstitution* pathSub = [[ELALocalPathSubstitutionService singleton] pathSubForRequest:request];

    //We don't have a mapping for this URL
    if (!pathSub)
        return NO;

    //If it's been fetched too many times, don't handle it
    if ([pathSub.timesLocalDataFetched intValue] > 0)
    {
        //Record that we refused it.
        [pathSub addHistoryItem:ELAPathSubstitutionHistoryRefusedByProtocol];
        return NO;
    }

    //Record that we handled it.
    [pathSub addHistoryItem:ELAPathSubstitutionHistoryHandledByProtocol];
    return YES;
}

可悲的是,似乎本地数据将进入缓存,但永远不会返回。这是一个日志片段:
History of [https://example.com/image.png]:
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryHandledByProtocol]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryCacheMiss]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryDataFetched]
[2014-04-29 18:01:53 +0000] = [ELAPathSubstitutionHistoryAddedToCache]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]

[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryCacheMiss]
[2014-04-29 18:02:11 +0000] = [ELAPathSubstitutionHistoryAddedToCache]
[2014-04-29 18:02:50 +0000] = [ELAPathSubstitutionHistoryRefusedByProtocol]
[2014-04-29 18:02:50 +0000] = [ELAPathSubstitutionHistoryCacheHit]

我的期望是,在协议第一次拒绝它后,它将导致几次缓存命中,但始终会将其视为未命中,从服务器中获取内容,然后再开始获取缓存命中。

我担心的是,我的NSURLProtocol子类以允许对其进行缓存的方式构造其响应,但是阻止了将其从缓存中取出。有任何想法吗?

提前致谢。 :)

最佳答案

与URL加载系统的缓存交互是NSURLProtocolClient对象的职责,该对象充当NSURLProtocol的客户端。如果请求使用NSURLRequestUseProtocolCachePolicy作为缓存策略,则协议的实施取决于应用正确的协议特定规则来确定是否应缓存响应。

在适合该协议的任何时间点,协议实现都在其客户端上调用 URLProtocol:cachedResponseIsValid: ,指示缓存的响应有效。然后,客户端应与URL加载系统的缓存层进行交互。

但是,由于系统提供给我们的客户是 private 且不透明的,因此您可能需要自己处理问题并与协议中的系统缓存进行交互。如果要采用该路径,可以直接使用NSURLCache。第一步是在协议中覆盖-cachedResponse。如果您仔细阅读文档,则默认实现仅根据传递给初始化程序的值进行设置。覆盖它,以便它访问shared URL cache(或您自己的 private URL缓存):

- (NSCachedURLResponse *) cachedResponse {
    return [[NSURLCache sharedURLCache] cachedResponseForRequest:[self request]];
}

现在,在通常需要在客户端上调用cachedResponseIsValid:的地方,还将NSCachedURLResponse存储到NSURLCache中。例如,当您具有一组完整的字节和一个响应时:
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:[self request]];

10-07 19:15
查看更多