来自服务器的所有http响应都带有标题,通知我们的应用程序不缓存响应:
Cache-Control: no-cache Pragma: no-cache Expires: 0
因此,如果您使用默认缓存策略“NSURLRequestUseProtocolCachePolicy”进行NSUrlRequests,则应用程序将始终从服务器加载数据.然而,我们需要缓存响应,明显的解决办法是将这些头设置为一段时间,例如(在后端),设置为10秒.但是我对解决方案感兴趣,如何绕过此策略并缓存每个请求10秒.
为此,您需要设置共享缓存.这可能在AppDelegate didFinishLaunchingWithOptions中完成:
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil]; [NSURLCache setSharedURLCache:URLCache];
然后,我们需要嵌入我们的代码强制缓存一个响应.如果您使用AFHttpClient的实例,则可以通过覆盖下面的方法并将高速缓存手动存储到共享缓存中来完成:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy]; NSMutableData *mutableData = [[cachedResponse data] mutableCopy]; NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly; // ... return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response] data:mutableData userInfo:mutableUserInfo storagePolicy:storagePolicy]; }
最后一件事是为请求设置cachePolicy.在我们的例子中,我们要为所有请求设置相同的缓存策略.所以再一次,如果你使用一个AFHttpClient的实例,那么可以通过覆盖下面的方法:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters { NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters]; request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; return request; }
到现在为止还挺好. “NSURLRequestReturnCacheDataElseLoad”使第一次执行请求,并从其他时间加载缓存的响应.问题是,目前还不清楚如何设置缓存到期时间,例如10秒.
解决方法
您可以实现一个自定义NSURLCache,它只返回尚未过期的缓存响应.
例:
#import "CustomURLCache.h" NSString * const EXPIRES_KEY = @"cache date"; int const CACHE_EXPIRES = -10; @implementation CustomURLCache // static method for activating this custom cache +(void)activate { CustomURLCache *urlCache = [[CustomURLCache alloc] initWithMemoryCapacity:(2*1024*1024) diskCapacity:(2*1024*1024) diskPath:nil] ; [NSURLCache setSharedURLCache:urlCache]; } -(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { NSCachedURLResponse * cachedResponse = [super cachedResponseForRequest:request]; if (cachedResponse) { NSDate* cacheDate = [[cachedResponse userInfo] objectForKey:EXPIRES_KEY]; if ([cacheDate timeIntervalSinceNow] < CACHE_EXPIRES) { [self removeCachedResponseForRequest:request]; cachedResponse = nil; } } return cachedResponse; } - (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request { NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary]; [userInfo setObject:[NSDate date] forKey:EXPIRES_KEY]; NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy]; [super storeCachedResponse:newCachedResponse forRequest:request]; } @end
如果这没有给你足够的控制权,那么我将使用如下的startLoading方法实现一个定制的NSURLProtocol,并将它与自定义缓存一起使用.
- (void)startLoading { NSMutableURLRequest *newRequest = [self.request mutableCopy]; [NSURLProtocol setProperty:@YES forKey:@"CacheSet" inRequest:newRequest]; 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]; } }
一些链接:
> Useful info on NSURLCache
> Creating a custom NSURLProtocol