一、YTKRequest繼承自YTKBaseRequest類,用於單獨封裝所有responseData緩存代碼。
// 首先YTKRequest的代碼如下: @interface YTKRequest : YTKBaseRequest //表示當前請求,是否忽略本地緩存responseData @property (nonatomic) BOOL ignoreCache; /// 返回當前緩存的對象 - (id)cacheJson; /// 是否當前的數據從緩存獲得 - (BOOL)isDataFromCache; /// 返回是否當前緩存需要更新【緩存是否超時】 - (BOOL)isCacheVersionExpired; /// 強制更新緩存【不使用緩存數據】 - (void)startWithoutCache; /// 手動將其他請求的JsonResponse寫入該請求的緩存 - (void)saveJsonResponseToCacheFile:(id)jsonResponse; /// 子類重寫方法【參數方法】 - (NSInteger)cacheTimeInSeconds; //當前請求指定時間內,使用緩存數據 - (long long)cacheVersion; //當前請求,指定使用版本號的緩存數據 - (id)cacheSensitiveData; @end
二、然后從YTKRequest的start方法看起,這個方法表示開始執行請求
// 該方法的執行邏輯,如下: - (void)start { //1. 當前請求,是否忽略緩存數據 if (self.ignoreCache) { [super start]; return; } //2. 當前請求,是否設置了緩存超時時間 if ([self cacheTimeInSeconds] < 0) { [super start]; return; } //3. 當前請求,對應的本地緩存數據的版本號,是否與當前請求指定的版本號一致 long long cacheVersionFileContent = [self cacheVersionFileContent]; if (cacheVersionFileContent != [self cacheVersion]) { [super start]; return; } //4. 當前請求,本地是否存在緩存數據文件 NSString *path = [self cacheFilePath]; NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:path isDirectory:nil]) { [super start]; return; } //5. 當前請求,對應的緩存數據,是否已經超時 int seconds = [self cacheFileDuration:path]; if (seconds < 0 || seconds > [self cacheTimeInSeconds]) { [super start]; return; } //6. 當前請求,對應的本地緩存數據文件,是否能夠取到responseJSON _cacheJson = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; if (_cacheJson == nil) { [super start]; return; } //7. 如果以上情況,都不滿足,表示本次請求的數據,來自本地緩存 _dataFromCache = YES; //8. 結束本次請求,執行回調Block,釋放Block [self requestCompleteFilter]; YTKRequest *strongSelf = self; [strongSelf.delegate requestFinished:strongSelf]; if (strongSelf.successCompletionBlock) { strongSelf.successCompletionBlock(strongSelf); } [strongSelf clearCompletionBlock]; }
三、本地緩存數據文件的管理方式:
管理方式一、按版本號
注意: 將一個responseJSON保存到本地,會同時產生2個文件 》文件一:保存responseData的文件 》文件二:標識本地保存responseData的版本號 //1. 得到responseJSON的緩存文件名 - (NSString *)cacheFileName { NSString *requestUrl = [self requestPath]; NSString *baseUrl = nil; if ([self baseURLType] == ZSYBaseURLBasic) { baseUrl = [YTKNetworkConfig sharedInstance].basicBaseUrl; } else if ([self baseURLType] == ZSYBaseURLWealthManagement) { baseUrl = [YTKNetworkConfig sharedInstance].cashBaseUrl; } id argument = [self cacheFileNameFilterForRequestArgument:[self requestArgument]]; NSString *requestInfo = [NSString stringWithFormat:@"Method:%ld Host:%@ Url:%@ Argument:%@ AppVersion:%@ Sensitive:%@", (long)[self requestMethod], baseUrl, requestUrl, argument, [YTKNetworkPrivate appVersionString], [self cacheSensitiveData]]; NSString *cacheFileName = [YTKNetworkPrivate md5StringFromString:requestInfo]; return cacheFileName; } //2. 2個緩存文件的全路徑 //文件一: 手機沙盒Document/LazyRequestCache/緩存文件名 //文件二: 手機沙盒Document/LazyRequestCache/緩存文件名.version - (NSString *)cacheFilePath { NSString *cacheFileName = [self cacheFileName]; NSString *path = [self cacheBasePath]; path = [path stringByAppendingPathComponent:cacheFileName]; return path; } //3. 讀取版本號文件中保存的NSNumber值 - (long long)cacheVersionFileContent { NSString *path = [self cacheVersionFilePath]; NSFileManager * fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:path isDirectory:nil]) { NSNumber *version = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; return [version longLongValue]; } else { return 0;//默認版本號=0 } } //4. 當前請求指定的版本號 與 本地緩存文件保存的版本號 ,對比后如果一致表示是合法緩存數據,否則是不合法緩存數據 long long cacheVersionFileContent = [self cacheVersionFileContent]; if (cacheVersionFileContent != [self cacheVersion]) { [super start]; return; } //5. 保存從服務器獲取到的responseJSON按版本號 - (void)saveJsonResponseToCacheFile:(id)jsonResponse { //1. 當前請求設置過緩存超時--》使用緩存 //2. responseJSON不是來自本地緩存文件 if ([self cacheTimeInSeconds] > 0 && ![self isDataFromCache]) { NSDictionary *json = jsonResponse; if (json != nil) { //保存responseJSON [NSKeyedArchiver archiveRootObject:json toFile:[self cacheFilePath]]; //保存當前request指定的版本號 [NSKeyedArchiver archiveRootObject:@([self cacheVersion]) toFile:[self cacheVersionFilePath]]; } } }
管理方式二、按超時時間
/** * * 核心: * 通過本地文件,創建時間 與 當前操作時間,的時間差,是否超過指定的時間長度 * */ - (int)cacheFileDuration:(NSString *)path { NSFileManager *fileManager = [NSFileManager defaultManager]; // get file attribute NSError *attributesRetrievalError = nil; NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:&attributesRetrievalError]; if (!attributes) { YTKLog(@"Error get attributes for file at %@: %@", path, attributesRetrievalError); return -1; } int seconds = -[[attributes fileModificationDate] timeIntervalSinceNow]; return seconds; } int seconds = [self cacheFileDuration:path]; if (seconds < 0 || seconds > [self cacheTimeInSeconds]) { [super start]; return; }