有時候,對同一個URL請求多次,返回的數據可能都是一樣的,比如服務器上的某張圖片,無論下載多少次,返回的數據都是一樣的。
上面的情況會造成以下問題
(1)用戶流量的浪費
(2)程序響應速度不夠快
解決上面的問題,一般考慮對數據進行緩存。
為了提高程序的響應速度,可以考慮使用緩存(內存緩存\硬盤緩存)r
第一次請求數據時,內存緩存中沒有數據,硬盤緩存中沒有數據。
? 當服務器返回數據時,需要做以下步驟
(1)使用服務器的數據(比如解析、顯示)
(2)將服務器的數據緩存到硬盤(沙盒)
此時緩存的情況是:內存緩存中有數據,硬盤緩存中有數據。
? 再次請求數據分為兩種情況:
(1)如果程序並沒有被關閉,一直在運行
請求數據-> 內存數據
(2)如果程序重新啟動
請求數據->硬盤數據-> 再次請求數據-> 內存數據
提示:數據從硬盤讀入內存-> 程序開啟-> 內存中一直有數據
? 由於GET請求一般用來查詢數據
? POST請求一般是發大量數據給服務器處理(變動性比較大)
=>因此一般只對GET請求進行緩存,而不對POST請求進行緩存
? 在iOS中,可以使用NSURLCache類緩存數據
? iOS 5之前:只支持內存緩存。從iOS 5開始:同時支持內存緩存和硬盤緩存
iOS中得緩存技術用到了NSURLCache類。
? 緩存原理:一個NSURLRequest對應一個NSCachedURLResponse
? 緩存技術:把緩存的數據都保存到數據庫中。
NSURLCache *cache = [NSURLCache sharedURLCache];
- (void)setMemoryCapacity:(NSUInteger)memoryCapacity;
- (void)setDiskCapacity:(NSUInteger)diskCapacity;
沙盒/Library/Caches
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
- (void)removeAllCachedResponses;
要想對某個GET請求進行數據緩存,非常簡單
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設置緩存策略
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
只要設置了緩存策略,系統會自動利用NSURLCache進行數據緩存
? NSURLRequestUseProtocolCachePolicy // 默認的緩存策略(取決於協議)
? NSURLRequestReloadIgnoringLocalCacheData // 忽略緩存,重新請求
? NSURLRequestReturnCacheDataElseLoad// 有緩存就用緩存,沒有緩存就重新請求
? NSURLRequestReturnCacheDataDontLoad// 有緩存就用緩存,沒有緩存就不發請求,當做請求出錯處理(用於離線模式)
NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未實現
NSURLRequestReloadRevalidatingCacheData // 未實現
NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未實現
緩存的設置需要根據具體的情況考慮,如果請求某個URL的返回數據:
(1)經常更新:不能用緩存!比如股票、彩票數據
(2)一成不變:果斷用緩存
(3)偶爾更新:可以定期更改緩存策略 或者 清除緩存
提示:如果大量使用緩存,會越積越大,建議定期清除緩存
//
// AppDelegate.m
// A-get緩存請求
//
// Created by Mr.Sunday on 15/4/27.
// Copyright (c) 2015年 Novogene. All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*===============設置網絡緩存==============*/
/**
內存緩存->4M
磁盤緩存->20M
diskPath 如果是 nil,會緩存到 cached 的 bundleId 目錄下
只要在 AppDelegate 中加入以下兩句話,今後所有的緩存處理,就不需要管了!
*/
NSURLCache *cathe = [[NSURLCache alloc] initWithMemoryCapacity:4*1024*1024 diskCapacity:20*1024*1024 diskPath:nil];
[NSURLCache setSharedURLCache:cathe];
/**
SDWebImage 的緩存
1. 緩存時間:1周
2. 處理緩存文件,監聽系統退出到後台的事件
- 遍歷緩存文件夾,刪除所有過期的文件
- 繼續遍歷緩存文件夾,將最大的文件刪除,一直刪除到緩存文件的大小和指定的“磁盤限額”一致,停止
*/
return YES;
}
//
// ViewController.m
// A-get緩存請求
//
// Created by Mr.Sunday on 15/4/27.
// Copyright (c) 2015年 Novogene. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIImageView *iconView;
//服務器返回的etag
@property (nonatomic, copy) NSString *etag;
//清楚所有緩存
- (void)removeAllCachedResponses;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
/**
1. 請求的緩存策略使用 >NSURLRequestReloadIgnoringCacheData<,忽略本地緩存
2. 服務器響應結束後,要記錄 Etag,服務器內容和本地緩存對比是否變化的重要依據!
3. 在發送請求時,設置 If-None-Match,並且傳入 etag
4. 連接結束後,要判斷響應頭的狀態碼,如果是 304,說明本地緩存內容沒有發生變化
*/
/*==================從本地緩存加載數據==============*/
/*
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
self.iconView.image = [UIImage imageWithData:cachedResponse.data];
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSURL *url = [NSURL URLWithString:@"http://mrsunday.local/ml.png"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
/**
*設置請求頭->所有的請求頭都是通過這種方法設置的
*如果etag length不為0,說明已經有緩存了
*/
if (self.etag.length > 0)
{
NSLog(@"設置 etag: %@", self.etag);
[request setValue:self.etag forHTTPHeaderField:@"IF-None-Match"];
}
//請求的默認方法是get(高頻使用)
NSLog(@"%@",request.HTTPMethod);
/**
*Etag = "\"4a0b9-514a2d804bd40\"";
*可以在請求中增加一個 etag 跟服務器返回的 etag 進行對比
*就能夠判斷服務器對應的資源是否發生變化,具體更新的時間,由request自行處理
*/
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
/**
*allHeaderFields 所有相應頭子端
*/
NSLog(@"%@ %@", httpResponse.allHeaderFields, httpResponse);
/**
*如果服務器的狀態碼是304,說明數據已經被緩存,服務器不再需要返回數據
*需要從本地緩存獲取被緩存的數據
*/
if (httpResponse.statusCode == 304)
{
NSLog(@"load local database");
/**
*針對http訪問的一個緩存類,提供了一個單例
*拿到被緩存的響應
*/
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
self.iconView.image = [UIImage imageWithData:cachedResponse.data];
return;
}
//記錄etag
self.etag = httpResponse.allHeaderFields[@"etag"];
self.iconView.image = [UIImage imageWithData:data];
}];
}
//記得要清除緩存請求!
- (void)removeAllCachedResponses
{
[self removeAllCachedResponses];
}
@end