您的位置:首页 > 其它

NSURLCache使用分析

2015-07-06 23:47 253 查看

NSURLCache他会自动拦截每一次的网络请求方法执行,主要有2个核心方法。

之前自己闲着没事,自己重写了一个NSURLCache,分享给大家,只是简单的Demo。

保存思路,借鉴的MKNetworkKit的代码思路。

做出一个内存缓存队列结构,来保存被缓存的response。

》保存,直接入队或者出队 ...

》将出队的缓存Item从内存删除,同时保存到本地文件

》将最后被访问的缓存Item重新放入到队尾,并删掉本地存放的文件,也就是读入到内存

》设置最大本地文件保存时间为一星期,定期清理

核心方法一: - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; 这个方法主要是用来查询request是否存在对应的缓存数据,注意:该方法并未提高如何查找缓存数据代码,需要自己实现。

// 查找缓存数据

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {

//1. 判断当前request是否可以被缓存(如果不可以,就不用查找缓存数据了)
if (![self requestCanCachable:request]) {

CacheDebugLog(@"Request:%@ 不允许被缓存\n", request);
return nil;
}

//2. 优先从内存字典查找
NSCachedURLResponse *cachedResponse = [self findCacheItemInMemory:request];

if (!cachedResponse) {

//3. 再考虑从本地文件查找
return [self findCacheResponseInDisk:request];
}

return cachedResponse;
}


// 判断当前request是否可以被缓存
- (BOOL)requestCanCachable:(NSURLRequest *)request {

BOOL isCachable = (request.cachePolicy == NSURLCacheStorageNotAllowed ||    \
[request.URL.absoluteString hasPrefix:@"file://"]  ||    \
[request.URL.absoluteString hasPrefix:@"data:"])  &&     \
[XZHURLCache networkAvailable];

return isCachable;
}


// 从内存字典查询缓存response

#pragma mark - 从内存字典对象 查找缓存数据
- (NSCachedURLResponse *)findCacheItemInMemory:(NSURLRequest *)request {

NSString *key = [XZHURLCache getRequestMD5Key:request];
BOOL isInMemoryCache = [_keysQueue keyIsInQueue:key];

if (!isInMemoryCache) {
return nil;
}

//从内存字典中找到了缓存项
CacheItem *cacheItem = _memoryCache[key];

if (![cacheItem isExpirat]) {

[_keysQueue removeObject:key];       //将找到的key从数组删除 (数组长度自动减1)
[_keysQueue my_enque:key];           //再将key入队尾部,作为最后被访问到的缓存response

return [XZHURLCache getCacheURLResponseWithData:[cacheItem cacheData] Request:request];
}

//缓存已经超时
return nil;
}


// 从本地文件系统 查找缓存数据
- (NSCachedURLResponse *)findCacheResponseInDisk:(NSURLRequest *)request {

NSString *path = [XZHURLCache responseFilePathForRequest:request RootPath:_cacheDirectory];

//从本地文件恢复对象
CacheItem *cachedItem = [CacheItem unArchiverFromPath:path];

if (cachedItem) {

if ([XZHURLCache networkAvailable]) {   //服务器可达,需要判断缓存是否超时,不可达直接返回缓存

if ([cachedItem isExpirat]) {
CacheDebugLog(@"Request: %@ 对应的缓存已经超时\n", request);

if (self.cacheTimeoutCallback) {
self.cacheTimeoutCallback();
}

return nil;
}
}

//1)服务器不可达 2)缓存未过期
CacheDebugLog(@"找到request: %@ 对应的缓存文件\n", request);
return [XZHURLCache getCacheURLResponseWithData:[cachedItem cacheData] Request:request];
}

CacheDebugLog(@"没有找到request: %@ 对应的缓存文件\n", request);
return nil;
}


核心方法二、

- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse

forRequest:(NSURLRequest *)request; 这个方法主要是用来保存response

- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse
forRequest:(NSURLRequest *)request
{
if ([[[request allHTTPHeaderFields] objectForKey:URLCACHE_CACHE_KEY] isEqualToString:@"YES"]) {

//保存response为缓存数据
[self saveCacheResponse:cachedResponse forRequest:request];
}

CacheDebugLog( @"CACHE currentDiskUsage:   %@", [NSString stringWithFormat:@"%lu/%lu", [self currentDiskUsage], [self diskCapacity]]);
CacheDebugLog( @"CACHE currentMemoryUsage: %@", [NSString stringWithFormat:@"%lu/%lu", [self currentMemoryUsage], [self memoryCapacity]]);
}


//保存response到内存和本地

- (void)saveCacheResponse:(NSCachedURLResponse *)cachedResponse
forRequest:(NSURLRequest *)request
{
CacheDebugLog(@"为Request:%@ 缓存response数据\n", request);

NSString *key = [XZHURLCache getRequestMD5Key:request];

CacheItem *cacheItem = [CacheItem createInstance];
cacheItem.lastModifyDate = [NSDate date];
cacheItem.cacheKey = key;
cacheItem.cacheData = [cachedResponse data];

//1. 设置缓存的最后修改时间
NSString *cacheMaxTime = [[request allHTTPHeaderFields] objectForKey:URLCACHE_EXPIRATION_AGE_KEY];
if ([cacheMaxTime isEqualToString:@"0"] || cacheMaxTime == nil) {
cacheItem.durationTime = MAX_AGE;
}else {
cacheItem.durationTime = [cacheMaxTime doubleValue];
}

BOOL isInMemoryCache = [_keysQueue keyIsInQueue:key];

//2. 将Item缓存项加入缓存

//2.1 已经存在于内存中
if (isInMemoryCache) {
_memoryCache[key] = cacheItem;

[_keysQueue removeObject:key];
[_keysQueue my_enque:key];

return;
}

//2.2 不在内存中
NSString *popedKey = [_keysQueue my_enque:key];

if (popedKey) {

//2.2.1.1 将退出队列item写入本地文件
CacheItem *popCacheItem = _memoryCache[popedKey];
NSString *path = [XZHURLCache responseFilePathForRequest:request RootPath:_cacheDirectory];
[popCacheItem archiverToPath:path];

//2.2.1.2 从内存删除
[_memoryCache removeObjectForKey:popedKey];

} else {

//2.2.2 放入内存
_memoryCache[key] = cacheItem;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: