iOS-网络-AFNetworking添加缓存层

为什么要添加一层缓存层?

  1. 系统有默认的缓存机制,用自己的缓存机制有绝对把控权
  2. 缓存的时效(A到B页面,B页面返回,恶意返回反复操作)
  3. 封装AFN没有的功能(如多网络任务异步、断点下载)
  4. 隔离AFN框架,AFN对项目的影响就比较小(隔离了业务)

1. 缓存机制

缓存机制.png

2. 缓存核心代码

/**
 核心方法

 @param method 请求方式
 @param urlStr 请求路径
 @param parameters 参数
 @param ignoreCache 是否不忽略缓存
 @param cacheDuration 缓存时效
 @param completionHandler 回调
 */
- (void)taskWithMethod:(NSString*)method
             urlString:(NSString*)urlStr
            parameters:(NSDictionary *)parameters
           ignoreCache:(BOOL)ignoreCache
         cacheDuration:(NSTimeInterval)cacheDuration
     completionHandler:(SYRequestCompletionHandler)completionHandler{
    
    // 1 url+参数 生成唯一码
    NSString *fileKeyFromUrl = SYConvertMD5FromParameter(urlStr, method, parameters);
    __weak typeof(self) weakSelf = self;
    
    // 2 缓存+没失效 判断是否有有效缓存
    if (!ignoreCache && [self.cache checkIfShouldUseCacheWithCacheDuration:cacheDuration cacheKey:fileKeyFromUrl]) {
        
        NSMutableDictionary *localCache = [NSMutableDictionary dictionary];
        NSDictionary *cacheDict = [self.cache searchCacheWithUrl:fileKeyFromUrl];
        [localCache setDictionary:cacheDict];
        if (cacheDict) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // 没有进行网络请求也回调异常block
                if (weakSelf.exceptionBlock) {
                    weakSelf.exceptionBlock(nil, localCache);
                }
                // 将缓存数据回调过去
                completionHandler(nil, YES, localCache); //error isCache result
            });
            return;
        }
    }
    
    // 5 处理网络返回来的数据,即缓存处理, 或者直接写个方法也可以
    SYRequestCompletionHandler newCompletionBlock = ^( NSError* error,  BOOL isCache, NSDictionary* result){
        //5.1处理缓存  ⚠️参数ignoreCache(网络task发起前,是否从本来缓存中获取数据)  cacheDuration(网络task结束后,是否对网络数据缓存)
        result = [NSMutableDictionary dictionaryWithDictionary:result];
        if (cacheDuration > 0) {// 缓存时效(即缓存时间)大于0
            if (result) {
                //存入缓存的条件block (比如:如果服务器数据有问题就不存入缓存)
                if (weakSelf.cacheConditionBlock) {
                    if (weakSelf.cacheConditionBlock(result)) { //根据result判断是否符合条件
                        [weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
                    }
                }else{
                    [weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
                }
            }
        }
        
        //5.2 其他情况异常回调
        dispatch_async(dispatch_get_main_queue(), ^{
            if (weakSelf.exceptionBlock) {
                weakSelf.exceptionBlock(error, (NSMutableDictionary*)result);
            }
            completionHandler(error, NO, 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) {
            /*
             4 处理数据 (处理数据的时候,需要处理下载的网络数据是否要缓存)
             这里可以直接使用 completionHandler,如果这样,网络返回的数据没有做缓存处理机制
             */
            newCompletionBlock(nil,NO, responseObject);
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            newCompletionBlock(error,NO, nil);;
        }];
    }else{
        task = [self.afHttpManager POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            newCompletionBlock(nil,NO, responseObject);
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            newCompletionBlock(error,NO, nil);
        }];
    }
    
    [task resume];
}

关于上面的代码:
第1步:生成唯一的key作为缓存的文件名
第2步:不忽略缓存并且缓存没失效就使用缓存
第3步:其他情况使用AFN
第4步:AFN请求成功,需要处理数据
第5步:处理网络返回来的数据,即是否写入缓存

3. 多网络任务异步

//tasks数组里面拿到任务, 使用dispatch_group_t执行
- (void)syBatchOfRequestOperations:(NSArray *)tasks
                     progressBlock:(void (^)(NSUInteger numberOfFinishedTasks, NSUInteger totalNumberOfTasks))progressBlock
                   completionBlock:(netSuccessbatchBlock)completionBlock{
    
    /*
     使用 dispatch_group_t 技术点
     dispatch_group_enter: 对group里面的任务数 +1
     dispatch_group_leave: 任务完成后,对group里面的任务数 -1
     dispatch_group_notify: 当group的任务数为0了,就会执行notify的block块操作,即所有的网络任务请求完了。
     */
    __weak typeof(self) weakSelf = self;
    dispatch_async(_SYNetQueue, ^{
        
        __block dispatch_group_t group = dispatch_group_create();
        [weakSelf.batchGroups addObject:group];
        
        __block NSInteger finishedTasksCount = 0;
        __block NSInteger totalNumberOfTasks = tasks.count;
        
        [tasks enumerateObjectsUsingBlock:^(SYNetRequestInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (obj) {
                // 网络任务启动前dispatch_group_enter
                dispatch_group_enter(group);
                
                SYRequestCompletionHandler newCompletionBlock = ^( NSError* error,  BOOL isCache, NSDictionary* result){
                    //先执行进度block
                    progressBlock(finishedTasksCount, totalNumberOfTasks);
                    //再执行完成block
                    if (obj.completionBlock) {
                        obj.completionBlock(error, isCache, result);
                    }

                    // 网络任务结束后dispatch_group_leave
                    dispatch_group_leave(group);
                };
                if ([obj.method isEqual:@"POST"]) {
                    [[SYNetMananger sharedInstance] syPostWithURLString:obj.urlStr parameters:obj.parameters ignoreCache:obj.ignoreCache cacheDuration:obj.cacheDuration completionHandler:newCompletionBlock];
                }else{
                    [[SYNetMananger sharedInstance] syGetWithURLString:obj.urlStr parameters:obj.parameters ignoreCache:obj.ignoreCache cacheDuration:obj.cacheDuration completionHandler:newCompletionBlock];
                }
            }
        }];
        //监听
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            [weakSelf.batchGroups removeObject:group];
            if (completionBlock) {
                completionBlock(tasks);
            }
        });
    });
}

关于上面的代码:

  1. (NSArray *)tasks 数组里面存放的是一个任务对象
  2. 关于dispatch_group_t:
    dispatch_group_enter:对group里面的任务数 +1。
    dispatch_group_leave:任务完成后,对group里面的任务数 -1。
    dispatch_group_notify:当group的任务数为0了,就会执行notify的block块操作,即所有的网络任务请求完了。
  3. 注意newCompletionBlock里面做了两件事:
    ① 回调一下任务进度block
    ② 回调单个任务的完成block
  4. 在dispatch_group_notify里面监听全部任务完成的block,然后回调

Demo地址:AFN添加缓存层

你可能感兴趣的:(iOS-网络-AFNetworking添加缓存层)