1.為什么要自己搭建緩存機制枢步?
- 系統(tǒng)的緩存機制把控性低中姜,為了讓自己隨意操作緩存
- 適應(yīng)特別的業(yè)務(wù)場景,我們可以自定義緩存的生命周期(如:惡意操作脚翘,在控制器之間不斷的push pop反復(fù)請求骂因;時效性低的網(wǎng)絡(luò)數(shù)據(jù))
- 從框架的角度我們可以解耦對AF的依賴炎咖,(比如替換網(wǎng)絡(luò)請求框架)
- AF沒有的功能,如多任務(wù)同步異步下載上傳
2.網(wǎng)絡(luò)緩存設(shè)計思路
- 1.發(fā)起網(wǎng)絡(luò) -> 是否讀取緩存 (是)-> 判斷緩存是否過期(沒過期)——>讀緩存——>返回緩存業(yè)務(wù)數(shù)據(jù)
- 2.發(fā)起網(wǎng)絡(luò) -> 是否讀取緩存 (是)->判斷緩存是否過期(過期了)——>請求網(wǎng)絡(luò)(AF操作)——>返回AF網(wǎng)絡(luò)數(shù)據(jù)
- 3 發(fā)起網(wǎng)絡(luò)->是否讀緩存(是否從緩存中拿數(shù)據(jù), 否)——>請求網(wǎng)絡(luò)(AF操作)——>返回AF網(wǎng)絡(luò)數(shù)據(jù)
3.設(shè)計接口時必要的一些參數(shù)
/**
GET請求
@param urlStr url地址
@param parameters 請求參數(shù)
@param ignoreCache 是否忽略緩存寒波,YES 忽略乘盼,NO 不忽略
@param cacheDuration 緩存時效
@param completionHandler 請求結(jié)果處理
*/
- (void)taskWithMethod:(NSString*)method
urlString:(NSString*)urlStr
parameters:(NSDictionary *)parameters
ignoreCache:(BOOL)ignoreCache
cacheDuration:(NSTimeInterval)cacheDuration
completionHandler:(SYRequestCompletionHandler)completionHandler;
4.架構(gòu)的簡易實現(xiàn)
- (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俄烁,說明緩存無效绸栅。
如果返回了數(shù)據(jù),那么緩存是有效猴娩。
*/
// NSMutableDictionary *localCache = [NSMutableDictionary dictionary];
NSDictionary *cacheDict = [self.cache searchCacheWithUrl:fileKeyFromUrl]; // 讀緩存
// [localCache setDictionary:cacheDict];
if (cacheDict) {
completionHandler(nil, YES, cacheDict); // error阴幌, isCache勺阐, result
return; // 注意到這里已經(jīng)結(jié)束了,不走下面
}
}
// 處理AF請求到的網(wǎng)絡(luò)數(shù)據(jù)矛双,是否緩存之類的
SYRequestCompletionHandler newCompletionBlock = ^(NSError* error, BOOL isCache, NSDictionary *result){
result = [NSMutableDictionary dictionaryWithDictionary:result];
//3.1處理網(wǎng)絡(luò)數(shù)據(jù)是否存入緩存(如果cacheDuration時效大于0渊抽,網(wǎng)絡(luò)數(shù)據(jù)就存入到緩存中)
if (cacheDuration > 0) {
// 假如網(wǎng)絡(luò)數(shù)據(jù)有問題,那么網(wǎng)絡(luò)數(shù)據(jù)不應(yīng)該保存緩存里面
// 因為不同的業(yè)務(wù)有不同錯誤code碼
if (weakSelf.cacheConditionBlock) { // 緩存條件
// 如果把服務(wù)端返回的code代入判斷block
if (weakSelf.cacheConditionBlock(result)) {
[weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl];
}
}else{
// 如果外部沒有判斷block议忽,默認任務(wù)數(shù)據(jù)存入緩存(不推薦)
[weakSelf.cache saveCacheData:result forKey:fileKeyFromUrl]; // 存入緩存
}
}
// 1 異常條件
if(weakSelf.exceptionBlock){
weakSelf.exceptionBlock(error, result);
}
completionHandler(error, isCache, 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) {
// 3.1處理網(wǎng)絡(luò)數(shù)據(jù)是否存入緩存
// 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屬性的單例懒闷,主要是在系統(tǒng)內(nèi)存資源緊張的時候會自動釋放內(nèi)存
- 其他方面NSCache與一般容器類型,如NSDictionary
6.其他需要注意的地方
- 這邊判斷是否是有緩存存在時栈幸,先從cache找愤估,再從本地找(這里采用歸檔做法)
- 儲存緩存時cache與本地同時存儲一份