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; } }
相关文章推荐
- 【Android Studio快捷键】之导入相应包声明(import packages)
- .NET委托解析(异步委托)
- memcache-命令-stats
- 摄像头参数设置了,不一定设置成功,需要确认是否,这个思维逻辑要有
- 学生管理系统
- 欢迎使用CSDN-markdown编辑器
- jedis简单使用
- mysql数据库插入汉字乱码问题
- 如何开发一个自己的 RubyGem?
- Spring学习(10)--- @Qualifier注解
- android ListView 在初始化时多次调用getView()原因分析
- [学习总结]6.29—7.5
- UVa 11520 Fill in the Square
- SpringMVC 入门 -- Handler编写
- 视图与触发器
- lc面试准备:Invert Binary Tree
- 在vim中针对c++自动补全
- css3动画2种区分
- java中compareTo和compare方法之比较
- java线程阻塞中断与LockSupport使用介绍(转)