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

Sco*_*Coy 2 objective-c nsurlcache nsurlprotocol ios

我编写了一个NSURLProtocol将检查http针对plist本地路径映射的URL的出站请求并改为提供本地内容,然后使用它来缓存它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];
}
Run Code Online (Sandbox Code Playgroud)

我限制了本地数据被提取到一个的次数.第一次获取它的意图来自于它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;
}
Run Code Online (Sandbox Code Playgroud)

可悲的是,似乎本地数据将进入缓存,但它不会再回来了.这是一个日志片段:

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]
Run Code Online (Sandbox Code Playgroud)

我的期望是,在第一次被协议拒绝后,它将导致一些缓存命中,但它总是将其视为未命中,从服务器获取内容,然后我开始获得缓存命中.

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

提前致谢.:)

que*_*ish 5

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

协议实现,无论何时适合于协议,都会调用URLProtocol:cachedResponseIsValid:它的客户端,指示缓存的响应是有效的.然后客户端应该与URL加载系统的缓存层进行交互.

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

- (NSCachedURLResponse *) cachedResponse {
    return [[NSURLCache sharedURLCache] cachedResponseForRequest:[self request]];
}
Run Code Online (Sandbox Code Playgroud)

现在在您通常会cachedResponseIsValid:在客户端上调用的地方,也可以将其存储NSCachedURLResponseNSURLCache.例如,当您有一组完整的字节和响应时:

[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:[self request]];
Run Code Online (Sandbox Code Playgroud)