美文网首页
【iOS】使用NSCache搭建自定义网络缓存层

【iOS】使用NSCache搭建自定义网络缓存层

作者: 找不到工作的iOS | 来源:发表于2018-05-23 15:31 被阅读63次

    1.为什么要自己搭建缓存机制?

    • 系统的缓存机制把控性低,为了让自己随意操作缓存
    • 适应特别的业务场景,我们可以自定义缓存的生命周期(如:恶意操作,在控制器之间不断的push pop反复请求;时效性低的网络数据)
    • 从框架的角度我们可以解耦对AF的依赖,(比如替换网络请求框架)
    • AF没有的功能,如多任务同步异步下载上传

    2.网络缓存设计思路

    • 1.发起网络 -> 是否读取缓存 (是)-> 判断缓存是否过期(没过期)——>读缓存——>返回缓存业务数据
    • 2.发起网络 -> 是否读取缓存 (是)->判断缓存是否过期(过期了)——>请求网络(AF操作)——>返回AF网络数据
    • 3 发起网络->是否读缓存(是否从缓存中拿数据, 否)——>请求网络(AF操作)——>返回AF网络数据

    3.设计接口时必要的一些参数

    /**
     GET请求
     
     @param urlStr url地址
     @param parameters 请求参数
     @param ignoreCache 是否忽略缓存,YES 忽略,NO 不忽略
     @param cacheDuration 缓存时效
     @param completionHandler 请求结果处理
     */
    - (void)taskWithMethod:(NSString*)method
                 urlString:(NSString*)urlStr
                parameters:(NSDictionary *)parameters
               ignoreCache:(BOOL)ignoreCache
             cacheDuration:(NSTimeInterval)cacheDuration
         completionHandler:(SYRequestCompletionHandler)completionHandler;
    

    4.架构的简易实现

    - (void)taskWithMethod:(NSString*)method
                 urlString:(NSString*)urlStr
                parameters:(NSDictionary *)parameters
               ignoreCache:(BOOL)ignoreCache
             cacheDuration:(NSTimeInterval)cacheDuration
         completionHandler:(SYRequestCompletionHandler)completionHandler{
        
        // 1缓存
        // 1.1 urlStr+method+parameters 生成一个唯一标识,个人选用md5的方式
        NSString *fileKeyFromUrl = SYConvertMD5FromParameter(urlStr, method, parameters);
        __weak typeof(self) weakSelf = self;
        
        // 1.2 缓存+失效 判断是否有有效缓存
        if (!ignoreCache && [self.cache checkIfShouldUseCacheWithCacheDuration:cacheDuration cacheKey:fileKeyFromUrl]) {
            /*
             
             [self.cache checkIfShouldUseCacheWithCacheDuration:cacheDuration cacheKey:fileKeyFromUrl]
             这个方法如果返回nil,说明缓存无效。
             如果返回了数据,那么缓存是有效。
             
             */
           // NSMutableDictionary *localCache = [NSMutableDictionary dictionary];
            NSDictionary *cacheDict = [self.cache searchCacheWithUrl:fileKeyFromUrl]; // 读缓存
           // [localCache setDictionary:cacheDict];
            if (cacheDict) {
                completionHandler(nil, YES, cacheDict); // error, isCache, result
                return; // 注意到这里已经结束了,不走下面
            }
        }
        
        // 处理AF请求到的网络数据,是否缓存之类的
        SYRequestCompletionHandler newCompletionBlock = ^(NSError* error, BOOL isCache, NSDictionary *result){
            
            result = [NSMutableDictionary dictionaryWithDictionary:result];
            //3.1处理网络数据是否存入缓存(如果cacheDuration时效大于0,网络数据就存入到缓存中)
            if (cacheDuration > 0) {
                
                // 假如网络数据有问题,那么网络数据不应该保存缓存里面
                // 因为不同的业务有不同错误code码
                
                if (weakSelf.cacheConditionBlock) { // 缓存条件
                    
                     // 如果把服务端返回的code代入判断block
                    if (weakSelf.cacheConditionBlock(result)) {
                        [weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
                    }
                }else{
                  // 如果外部没有判断block,默认任务数据存入缓存(不推荐)
                    [weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl]; // 存入缓存
                }
            }
                
            // 1 异常条件
            if(weakSelf.exceptionBlock){
                weakSelf.exceptionBlock(error, result);
            }
            
            completionHandler(error, isCache, result);
    
        };
        
        
        
        //3  发起AF网络任务
        NSURLSessionTask *task = nil;
        if ([method isEqualToString:@"GET"]) {
            
            task = [self.afHttpManager GET:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                
                // 3.1处理网络数据是否存入缓存
               // completionHandler(nil, NO, responseObject);
                newCompletionBlock(nil, NO, responseObject);
               
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                
                //completionHandler(error, NO, nil);
                newCompletionBlock(error, NO, nil);
            }];
            
        }else{
            
            task = [self.afHttpManager POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                
              //  completionHandler(nil, NO, responseObject);
                newCompletionBlock(nil, NO, responseObject);
                
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                
               // completionHandler(error, NO, nil);
                newCompletionBlock(error, NO, nil);
            }];
            
        }
        
        [task resume];
    }
    

    5.NSCache

    • 缓存方面使用包含NSCache属性的单例,主要是在系统内存资源紧张的时候会自动释放内存
    • 其他方面NSCache与一般容器类型,如NSDictionary

    6.其他需要注意的地方

    • 这边判断是否是有缓存存在时,先从cache找,再从本地找(这里采用归档做法)
    • 储存缓存时cache与本地同时存储一份

    相关文章

      网友评论

          本文标题:【iOS】使用NSCache搭建自定义网络缓存层

          本文链接:https://www.haomeiwen.com/subject/witrjftx.html