為什么要添加一層緩存層?
- 系統(tǒng)有默認(rèn)的緩存機(jī)制,用自己的緩存機(jī)制有絕對(duì)把控權(quán)
- 緩存的時(shí)效(A到B頁面,B頁面返回,惡意返回反復(fù)操作)
- 封裝AFN沒有的功能(如多網(wǎng)絡(luò)任務(wù)異步、斷點(diǎn)下載)
- 隔離AFN框架,AFN對(duì)項(xiàng)目的影響就比較小(隔離了業(yè)務(wù))
1. 緩存機(jī)制

緩存機(jī)制.png
2. 緩存核心代碼
/**
核心方法
@param method 請求方式
@param urlStr 請求路徑
@param parameters 參數(shù)
@param ignoreCache 是否不忽略緩存
@param cacheDuration 緩存時(shí)效
@param completionHandler 回調(diào)
*/
- (void)taskWithMethod:(NSString*)method
urlString:(NSString*)urlStr
parameters:(NSDictionary *)parameters
ignoreCache:(BOOL)ignoreCache
cacheDuration:(NSTimeInterval)cacheDuration
completionHandler:(SYRequestCompletionHandler)completionHandler{
// 1 url+參數(shù) 生成唯一碼
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(), ^{
// 沒有進(jìn)行網(wǎng)絡(luò)請求也回調(diào)異常block
if (weakSelf.exceptionBlock) {
weakSelf.exceptionBlock(nil, localCache);
}
// 將緩存數(shù)據(jù)回調(diào)過去
completionHandler(nil, YES, localCache); //error isCache result
});
return;
}
}
// 5 處理網(wǎng)絡(luò)返回來的數(shù)據(jù),即緩存處理, 或者直接寫個(gè)方法也可以
SYRequestCompletionHandler newCompletionBlock = ^( NSError* error, BOOL isCache, NSDictionary* result){
//5.1處理緩存 ??參數(shù)ignoreCache(網(wǎng)絡(luò)task發(fā)起前,是否從本來緩存中獲取數(shù)據(jù)) cacheDuration(網(wǎng)絡(luò)task結(jié)束后,是否對(duì)網(wǎng)絡(luò)數(shù)據(jù)緩存)
result = [NSMutableDictionary dictionaryWithDictionary:result];
if (cacheDuration > 0) {// 緩存時(shí)效(即緩存時(shí)間)大于0
if (result) {
//存入緩存的條件block (比如:如果服務(wù)器數(shù)據(jù)有問題就不存入緩存)
if (weakSelf.cacheConditionBlock) {
if (weakSelf.cacheConditionBlock(result)) { //根據(jù)result判斷是否符合條件
[weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
}
}else{
[weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
}
}
}
//5.2 其他情況異?;卣{(diào)
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.exceptionBlock) {
weakSelf.exceptionBlock(error, (NSMutableDictionary*)result);
}
completionHandler(error, NO, result);
});
};
//3 發(fā)起AF網(wǎng)絡(luò)任務(wù)
NSURLSessionTask *task = nil;
if ([method isEqualToString:@"GET"]) {
task = [self.afHttpManager GET:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
/*
4 處理數(shù)據(jù) (處理數(shù)據(jù)的時(shí)候,需要處理下載的網(wǎng)絡(luò)數(shù)據(jù)是否要緩存)
這里可以直接使用 completionHandler,如果這樣,網(wǎng)絡(luò)返回的數(shù)據(jù)沒有做緩存處理機(jī)制
*/
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];
}
關(guān)于上面的代碼:
第1步:生成唯一的key作為緩存的文件名
第2步:不忽略緩存并且緩存沒失效就使用緩存
第3步:其他情況使用AFN
第4步:AFN請求成功,需要處理數(shù)據(jù)
第5步:處理網(wǎng)絡(luò)返回來的數(shù)據(jù),即是否寫入緩存
3. 多網(wǎng)絡(luò)任務(wù)異步
//tasks數(shù)組里面拿到任務(wù), 使用dispatch_group_t執(zhí)行
- (void)syBatchOfRequestOperations:(NSArray<SYNetRequestInfo *> *)tasks
progressBlock:(void (^)(NSUInteger numberOfFinishedTasks, NSUInteger totalNumberOfTasks))progressBlock
completionBlock:(netSuccessbatchBlock)completionBlock{
/*
使用 dispatch_group_t 技術(shù)點(diǎn)
dispatch_group_enter: 對(duì)group里面的任務(wù)數(shù) +1
dispatch_group_leave: 任務(wù)完成后,對(duì)group里面的任務(wù)數(shù) -1
dispatch_group_notify: 當(dāng)group的任務(wù)數(shù)為0了,就會(huì)執(zhí)行notify的block塊操作,即所有的網(wǎng)絡(luò)任務(wù)請求完了。
*/
__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) {
// 網(wǎng)絡(luò)任務(wù)啟動(dòng)前dispatch_group_enter
dispatch_group_enter(group);
SYRequestCompletionHandler newCompletionBlock = ^( NSError* error, BOOL isCache, NSDictionary* result){
//先執(zhí)行進(jìn)度block
progressBlock(finishedTasksCount, totalNumberOfTasks);
//再執(zhí)行完成block
if (obj.completionBlock) {
obj.completionBlock(error, isCache, result);
}
// 網(wǎng)絡(luò)任務(wù)結(jié)束后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];
}
}
}];
//監(jiān)聽
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[weakSelf.batchGroups removeObject:group];
if (completionBlock) {
completionBlock(tasks);
}
});
});
}
關(guān)于上面的代碼:
- (NSArray<SYNetRequestInfo *> *)tasks 數(shù)組里面存放的是一個(gè)任務(wù)對(duì)象
- 關(guān)于dispatch_group_t:
dispatch_group_enter:對(duì)group里面的任務(wù)數(shù) +1。
dispatch_group_leave:任務(wù)完成后,對(duì)group里面的任務(wù)數(shù) -1。
dispatch_group_notify:當(dāng)group的任務(wù)數(shù)為0了,就會(huì)執(zhí)行notify的block塊操作,即所有的網(wǎng)絡(luò)任務(wù)請求完了。 - 注意newCompletionBlock里面做了兩件事:
① 回調(diào)一下任務(wù)進(jìn)度block
② 回調(diào)單個(gè)任務(wù)的完成block - 在dispatch_group_notify里面監(jiān)聽全部任務(wù)完成的block,然后回調(diào)
Demo地址:AFN添加緩存層