ios - 如何使用 NSURLCache 缓存 NSURLProtocol 提供的内容

标签 ios objective-c nsurlcache nsurlprotocol

我编写了一个 NSURLProtocol,它将根据 URL 到本地路径映射的 plist 检查出站 http 请求,并提供本地内容,然后使用 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 来检查它是否应该来自 < strong>缓存或网络:

+ (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]

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

我担心的是,我的 NSURLProtocol 子类以允许缓存响应的方式构造其响应,但阻止它们从缓存中拉出。有什么想法吗?

提前致谢。 :)

最佳答案

与 URL 加载系统的缓存进行交互是作为 NSURLProtocol 客户端的 NSURLProtocolClient 对象的责任。如果请求使用 NSURLRequestUseProtocolCachePolicy 作为缓存策略,则由协议(protocol)实现来应用正确的协议(protocol)特定规则来确定是否应缓存响应。

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

但是,由于系统向我们提供的客户端是私有(private)且不透明的,因此您可能希望自己掌握事务并在协议(protocol)中与系统缓存进行交互。如果你想走这条路,你可以直接使用 NSURLCache。第一步是覆盖协议(protocol)中的 -cachedResponse。如果您仔细阅读文档,默认实现仅根据传递到初始值设定项的值来设置此值。覆盖它,以便它访问 shared URL cache (或者您自己的私有(private) URL 缓存):

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

现在,在客户端上通常调用 cachedResponseIsValid: 的地方,还将 NSCachedURLResponse 存储到 NSURLCache 中。例如,当您拥有完整的字节集和响应时:

[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:[self request]];

关于ios - 如何使用 NSURLCache 缓存 NSURLProtocol 提供的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23374675/

相关文章:

ios - 使用 Storyboard时 UIView 委托(delegate)在什么阶段设置

ios - 如何 [NSURLCache cachedResponseForRequest :] do its matching?

ios - CFURLCacheNode swift 泄漏?

iphone - 始终在 rootViewController 中打开应用程序

php - 比较 iPhone 上 UIImage 上的 MD5 哈希和服务器上的文件

ios - 当响应包含在数组中时,RestKit POSTed 托管对象变得重复

iPhone -> NSNumberFormatter - 没有货币代码的价格

ios - iPhone : Detecting Tap in MKMapView

objective-c - 如何更改特定索引处的 NSMutableArray 的值

iOS URLCache 在不应该的时候缓存(恕我直言)