IOS 數(shù)據(jù)大體可以分為兩類,
- 靜態(tài)數(shù)據(jù)赖阻,例如文字,本地的圖標踱蠢。
- 需要通過網(wǎng)絡請求去重新獲得的數(shù)據(jù)火欧,例如服務器上的圖片的url棋电。
而這篇文章我主要寫的是如何去處理數(shù)據(jù)的緩存,也就是在第一次網(wǎng)絡加載成功的同時把網(wǎng)絡數(shù)據(jù)的本地持久化苇侵。從而在沒有網(wǎng)絡的情況下赶盔,仍然可以在app界面中有之前緩存過的數(shù)據(jù)。
靜態(tài)緩存數(shù)據(jù):
靜態(tài)數(shù)據(jù)的緩存榆浓,利用AFN網(wǎng)絡數(shù)據(jù)的請求成功的同時于未,將數(shù)據(jù)以數(shù)據(jù)表的形式寫入本地的SQLite文件中。
該方法通過重新封裝AFNetworking,在網(wǎng)絡請求的同時會傳入一個標識數(shù)據(jù)表的參數(shù)陡鹃,并在網(wǎng)絡請求的最底層烘浦,網(wǎng)絡數(shù)據(jù)請求成功的時候?qū)?shù)據(jù)寫到數(shù)據(jù)表中。而當網(wǎng)絡請求失敗的時候萍鲸,同樣會在底層中利用數(shù)據(jù)表的參數(shù)得到相應的在sqlite文件中的數(shù)據(jù)闷叉。(如果是第一次請求出現(xiàn)失敗,那肯定是沒有數(shù)據(jù)的脊阴。)
以上的內(nèi)容都是基于第一次網(wǎng)絡請求成功后握侧,之后出現(xiàn)的網(wǎng)絡失敗的情況來說明的。
SQLite的第三方封裝嘿期,個人使用的是FMDB框架品擎。
下面就代碼說明一下,數(shù)據(jù)請求的入口:
- (void)sendRequest {
[[FMAppWebRequest sharedClient] homePageWithParam:nil SQTableName:@"homeCacheData" success:^(id responseObject) {
NSLog(@"%@",responseObject);
} failure:^(NSError *error, id cacheData) {
NSLog(@"%@",cacheData);
}];
}
當然這是經(jīng)過封裝了的备徐,這既是網(wǎng)絡的入口萄传,也是數(shù)據(jù)的出口。有一個用來裝數(shù)據(jù)的數(shù)據(jù)表參數(shù)坦喘,以及在網(wǎng)絡請求失敗后會有一個id 的數(shù)據(jù)返回盲再。(默認的是一個字典形式的數(shù)據(jù)。)
這個網(wǎng)絡請求的封裝在FMHTTPClient.h文件中瓣铣。
但對網(wǎng)絡數(shù)據(jù)的本地持久化的封裝實在AFNetworking 的最底層文件AFHTTPRequestOperation.h中答朋。
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error, id cacheData))failure
attachSQTableName:(NSString *)tableName
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
if (self.completionGroup) {
dispatch_group_enter(self.completionGroup);
}
dispatch_async(http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
id cacheData = [FMSQHelpModel dataDicFromSQTable:tableName];
failure(self, self.error, cacheData);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
id cacheData = [FMSQHelpModel dataDicFromSQTable:tableName];
failure(self, self.error, cacheData);
});
}
} else {
if (success) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
[FMSQHelpModel saveDicFromNet:responseObject inSQTable:tableName];
success(self, responseObject);
});
}
}
}
if (self.completionGroup) {
dispatch_group_leave(self.completionGroup);
}
});
};
#pragma clang diagnostic pop
}
在數(shù)據(jù)請求成功時,進行了下一步操作
[FMSQHelpModel saveDicFromNet:responseObject inSQTable:tableName];
這是將網(wǎng)絡請求成功的數(shù)據(jù)寫入到相應的數(shù)據(jù)表中的操作棠笑。
而在網(wǎng)絡請求失敗的時候梦碗,會用這樣的一步操作。
id cacheData = [FMSQHelpModel dataDicFromSQTable:tableName];
這是從相應的數(shù)據(jù)表中去取已經(jīng)放在里面的數(shù)據(jù)。
當然這些語句也是經(jīng)過封裝后的。
具體的代碼在FMSQHelpModel.h文件中敷搪,這里用到了FMDB框架,主要是通過SQL語句對數(shù)據(jù)的寫入和讀取斩例。
這樣就把數(shù)據(jù)以字典的形式存入到數(shù)據(jù)表中了,在網(wǎng)絡請求失敗后同樣可以拿到以字典為數(shù)據(jù)的對象(和網(wǎng)絡請求成功時返回的一樣的數(shù)據(jù)格式的對象)从橘,這樣的好處是我們根本不需要在另寫一個數(shù)據(jù)的解析方法念赶,直接用網(wǎng)絡請求成功時的解析方法即可础钠。
這樣我們就解決了靜態(tài)數(shù)據(jù)的緩存問題了。
URL請求數(shù)據(jù):
例如說在字典中肯定會有一些圖片的url叉谜,這樣在沒有網(wǎng)絡的情況下我們只能從數(shù)據(jù)表中拿到圖片的url旗吁,但不能生成圖片。這時候我們就要使用另外的方法了停局,也就是對圖片的緩存了很钓。
對圖片的緩存我們IOS都會想到SDWebImage,當然它下載圖片的一整套的框架,只不過我們只是熟悉它的網(wǎng)絡下載圖片的API,對其中的圖片緩存并沒有多少的了解董栽。
直接上它對于圖片緩存的代碼吧码倦!
-(void)setModel:(FMRecommendModel *)model
{
_model = model;
[FMSQHelpModel cacheImageWithUrlStr:model.works_url inImageView:_phoneShellImage imageBlock:^(UIImage *image) {
}];
}
這是在model的set方法中用到的
+ (void)cacheImageWithUrlStr:(NSString *)urlStr
inImageView:(UIImageView *)imageView
imageBlock:(void (^)(UIImage *))completion {
UIImage *exitImg = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:urlStr];
if (exitImg) {
imageView.image = exitImg;
completion(exitImg);
return;
}
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:urlStr] options:SDWebImageRetryFailed progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
NSString *key = [imageURL absoluteString];
if (image) {
imageView.image = image;
[[SDImageCache sharedImageCache] storeImage:image forKey:key toDisk:YES];
}else {
imageView.image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key];
[[SDImageCache sharedImageCache] cleanDisk];
}
completion(image);
}];
}
這樣就利用SDWebImage框架對圖片url的數(shù)據(jù)進行了緩存了。
下面就是這個demo的地址裆泳,其中的服務器地址需要填寫自己公司的服務器地址叹洲。demo 中只是對第一種情況有相應的代碼柠硕,第二種需要你在自己項目中調(diào)用上面的方法即可工禾。