HTTP协议(三)之缓存
当我们对容一个URL可能多次请求,并且请求返回的数据都是一样的,比如服务器上的图片,无论下载多少次都是一样的,这个时候我们就可以使用缓存,优点主要有两点:
1、避免用户浪费流量 2、提高程序的响应速度
缓存分为内存缓存(沙盒缓存)和硬盘缓存。当我们第一次请求数据时,先检查内存缓存中有没有缓存数据,如果有就直接使用内存缓存中的数据,如果没有就检查硬盘缓存中有无缓存数据,如果有就使用,如果没有就向服务器请求数据。当服务器返回数据后,先使用返回的数据,然后将返回的数据缓存到硬盘中。此时再次请求这个数据就可以直接使用内存中的缓存了。
在HTTP协议中,GET请求一般用来请求数据,而POST一般用来给服务器发送大量数据,所以我们一般对GET请求的数据进行缓存,不必对POST请求进行缓存。
在iOS中,可以使用NSURLCache进行缓存。iOS中使用缓存策略来使用不同的缓存方案,提供了7种缓存策略:
-
NSURLRequestUseProtocolCachePolicy:默认的缓存策略,取决于HTTP协议中是否需要缓存。
-
NSURLRequestReloadIgnoringLocalCacheData:忽略缓存,重新请求。
-
NSURLRequestReloadIgnoringLocalAndRemoteCacheData:未实现
-
NSURLRequestReloadIgnoringCacheData:和第2种相同。
-
NSURLRequestReturnCacheDataElseLoad:有缓存使用缓存,没有就重新请求。
-
NSURLRequestReturnCacheDontLoad:只使用缓存,不发送请求(用于离线模式)
-
NSURLRequestReloadRevalidatingCacheData:未实现
我们在开发时一般使用NSURLRequestReturnCacheDataElseLoad缓存策略,当我们发送请求返回数据后,数据会再内存和沙盒中缓存,再次请求这个数据的时候会从内存或者沙盒中取出数据,不再向服务器发送请求。
- (IBAction)getData:(id)sender { //创建请求 NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/video?method=get&type=JSON"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //设置缓存策略 request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; //发送请求,获得数据 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"dict:%@", dict); }]; }
NSURLCache是一个非常重要的单例,它管理应用的所有缓存和缓存的属性设置。
获取/设置缓存大小:
- (NSUInteger)memoryCapacity; /*! @method diskCapacity @abstract Returns the on-disk capacity of the receiver. @result The on-disk capacity, measured in bytes, for the receiver. */ - (NSUInteger)diskCapacity; /*! @method setMemoryCapacity: @abstract Sets the in-memory capacity of the receiver. @discussion At the time this call is made, the in-memory cache will truncate its contents to the size given, if necessary. @param memoryCapacity the new in-memory capacity, measured in bytes, for the receiver. */ - (void)setMemoryCapacity:(NSUInteger)memoryCapacity; /*! @method setDiskCapacity: @abstract Sets the on-disk capacity of the receiver. @discussion At the time this call is made, the on-disk cache will truncate its contents to the size given, if necessary. @param diskCapacity the new on-disk capacity, measured in bytes, for the receiver. */ - (void)setDiskCapacity:(NSUInteger)diskCapacity;
内存使用量:
/*! @method currentMemoryUsage @abstract Returns the current amount of space consumed by the in-memory cache of the receiver. @discussion This size, measured in bytes, indicates the current usage of the in-memory cache. @result the current usage of the in-memory cache of the receiver. */ - (NSUInteger)currentMemoryUsage; /*! @method currentDiskUsage @abstract Returns the current amount of space consumed by the on-disk cache of the receiver. @discussion This size, measured in bytes, indicates the current usage of the on-disk cache. @result the current usage of the on-disk cache of the receiver. */ - (NSUInteger)currentDiskUsage;
清除缓存:
/*! @method removeCachedResponseForRequest: @abstract Removes the NSCachedURLResponse from the cache that is stored using the given request. @discussion No action is taken if there is no NSCachedURLResponse stored with the given request. @param request the NSURLRequest to use as a key for the lookup. */ - (void)removeCachedResponseForRequest:(NSURLRequest *)request; /*! @method removeAllCachedResponses @abstract Clears the given cache, removing all NSCachedURLResponse objects that it stores. */ - (void)removeAllCachedResponses;
获取/保存某个请求的缓存:
/*! @method cachedResponseForRequest: @abstract Returns the NSCachedURLResponse stored in the cache with the given request. @discussion The method returns nil if there is no NSCachedURLResponse stored using the given request. @param request the NSURLRequest to use as a key for the lookup. @result The NSCachedURLResponse stored in the cache with the given request, or nil if there is no NSCachedURLResponse stored with the given request. */ - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; /*! @method storeCachedResponse:forRequest: @abstract Stores the given NSCachedURLResponse in the cache using the given request. @param cachedResponse The cached response to store. @param request the NSURLRequest to use as a key for the storage. */ - (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request;
我们可以用下面这个方法手动获取某个请求:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
NSCachedURLResponse就是一个请求对应的缓存对象,从这个缓存对象中可以获取对应的缓存数据:
/*! @method data @abstract Returns the data of the receiver. @result The data of the receiver. */ - (NSData *)data;
下面是一个获取天气信息的demo,使用NSURLRequestReturnCacheDataElseLoad缓存策略:
- (IBAction)getData:(id)sender { //创建请求 NSURL *url = [NSURL URLWithString:@"http://www.weather.com.cn/adat/cityinfo/101010100.html"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //设置缓存策略 request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; //获取缓存数据 NSURLCache *cache = [NSURLCache sharedURLCache]; NSCachedURLResponse *cachedResponse = [cache cachedResponseForRequest:request]; if (cachedResponse) { NSData *data = cachedResponse.data; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"有缓存数据:%@", dict); }else { NSLog(@"没有缓存数据"); } //发送请求,获得数据 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"dict:%@", dict); }]; }
第一次请求的输出:
2015-07-10 09:56:59.249 CacheDemo[21401:607] 没有缓存数据 2015-07-10 09:56:59.438 CacheDemo[21401:607] dict:{ weatherinfo = { city = "U5317U4eac"; cityid = 101010100; img1 = "d1.gif"; img2 = "n1.gif"; ptime = "08:00"; temp1 = "15U2103"; temp2 = "5U2103"; weather = "U591aU4e91"; }; }
再次请求的输出:
2015-07-10 09:57:34.057 CacheDemo[21423:607] 有缓存数据:{ weatherinfo = { city = "U5317U4eac"; cityid = 101010100; img1 = "d1.gif"; img2 = "n1.gif"; ptime = "08:00"; temp1 = "15U2103"; temp2 = "5U2103"; weather = "U591aU4e91"; }; } 2015-07-10 09:57:34.063 CacheDemo[21423:607] dict:{ weatherinfo = { city = "U5317U4eac"; cityid = 101010100; img1 = "d1.gif"; img2 = "n1.gif"; ptime = "08:00"; temp1 = "15U2103"; temp2 = "5U2103"; weather = "U591aU4e91"; }; }
OK,可以使用缓存数据了。如果缓存数据过期那就要清除缓存,下面是清除缓存的实例:
- (IBAction)clearCache:(id)sender { //清除所有缓存 NSLog(@"清除所有缓存"); [[NSURLCache sharedURLCache] removeAllCachedResponses]; }
清除缓存后再次发送请求的输出:
2015-07-10 10:03:17.266 CacheDemo[21547:607] 清除所有缓存 2015-07-10 10:03:18.659 CacheDemo[21547:607] 没有缓存数据 2015-07-10 10:03:19.765 CacheDemo[21547:607] dict:{ weatherinfo = { city = "U5317U4eac"; cityid = 101010100; img1 = "d1.gif"; img2 = "n1.gif"; ptime = "08:00"; temp1 = "15U2103"; temp2 = "5U2103"; weather = "U591aU4e91"; }; }
下面这个流程图很好的展示了如何使用缓存:
最后是Demo的下载地址:CacheDemo