您的位置:首页 > 理论基础 > 计算机网络

AFNetworking网络请求缓存

2016-09-20 16:41 309 查看
http://devtian.me/2015/03/24/translate-how-does-cache-work-in-AFNetworking/http://www.cnblogs.com/wendingding/p/3950198.html

(译)缓存在AFNetworking中是如何工作的?AFImageCache和NSUrlCache给你答案

发表于 2015-03-24   |   0 Comments如果你是一名使用Mattt Thompson网络框架
AFNetworking
的iOS开发者(如果你不是,那还等什么呢?),也许你对这个框架中的缓存机制很好奇或者疑惑,并想学习如何在自己的app中充分利用这种机制。
AFNetworking
实际上使用了两个独立的缓存机制:AFImagecache:一个提供图片内存缓存的类,继承自
NSCache
。NSURLCache:
NSURLConnection's
默认的URL缓存机制,用于存储
NSURLResponse
对象:一个默认缓存在内存,通过配置可以缓存到磁盘的类。为了理解每个缓存系统是如何工作的,我们看一下他们是如何定义的。

AFImageCache是如何工作的

AFImageCache
UIImageView+AFNetworking
分类的一部分。它继承自
NSCache
,通过一个URL字符串作为它的key(从
NSURLRequest
中获取)来存储
UIImage
对象。AFImageCache定义:
@interface AFImageCache : NSCache <AFImageCache>// singleton instantiation :+ (id <AFImageCache>)sharedImageCache {static AFImageCache *_af_defaultImageCache = nil;static dispatch_once_t oncePredicate;dispatch_once(&oncePredicate, ^{_af_defaultImageCache = [[AFImageCache alloc] init];// clears out cache on memory warning :[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) {[_af_defaultImageCache removeAllObjects];}];});// key from [[NSURLRequest URL] absoluteString] :static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) {return [[request URL] absoluteString];}@implementation AFImageCache// write to cache if proper policy on NSURLRequest :- (UIImage *)cachedImageForRequest:(NSURLRequest *)request {switch ([request cachePolicy]) {case NSURLRequestReloadIgnoringCacheData:case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:return nil;default:break;}return [self objectForKey:AFImageCacheKeyFromURLRequest(request)];}// read from cache :- (void)cacheImage:(UIImage *)imageforRequest:(NSURLRequest *)request {if (image && request) {[self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)];}}
AFImageCache
 从 
AFNetworking
 2.1开始可以进行配置了。有一个公共方法
setSharedImageCache
。详细文档可以看这里 。它把所有可访问的
UIImage
对象存到了
NSCache
。当
UIImage
对象释放之后
NSCache
会进行处理。如果你想观察images什么时候释放,可以实现
NSCacheDelegate
cache:willEvictObject
方法

NSURLCache如何工作

默认是可以的,但最好还是手动配置一下既然
AFNetworking
使用
NSURLConnection
,它利用了原生的缓存机制
NSURLCache
NSURLCache
缓存了从服务器返回的
NSURLResponse
对象。
NSURLCache
shareCache
方法默认是可以使用的,缓存获取的内容。不幸的是,它的默认配置只是缓存在内存并没有写到硬盘。为了解决这个问题,你可以声明一个 
sharedCache
,像这样:
1234
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024diskCapacity:100 * 1024 * 1024diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];
这样,我们声明了一个2M内存,100M磁盘空间的
NSURLCache
对NSURLRequest对象设置缓存策略
NSURLCache
对每个
NSURLRequest
对象都会遵守缓存策略(NSURLRequestCachePolicy)。策略定义如下:NSURLRequestUseProtocolCachePolicy:指定定义在协议实现里的缓存逻辑被用于URL请求。这是URL请求的默认策略NSURLRequestReloadIgnoringLocalCacheData:忽略本地缓存,从源加载NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地&服务器缓存,从源加载NSURLRequestReturnCacheDataElseLoad:先从缓存加载,如果没有缓存,从源加载NSURLRequestReturnCacheDataDontLoad离线模式,加载缓存数据(无论是否过期),不从源加载NSURLRequestReloadRevalidatingCacheData存在的缓存数据先确认有效性,无效的话从源加载用NSURLCache缓存到磁盘Cache-Control HTTP Header
Cache-Control
或者
Expires
 header 必须在从服务器返回的 HTTP response header 中,用于客户端的缓存(Cache-Control header 优先权高于 Expires header)。这里边有很多需要注意的地方,
Cache Control
可以有被定义为 
max-age
的参数(在更新响应之前缓存多长时间),public/private 访问,或者 
no-cache
(不缓存响应数据),这里有一个关于HTTP cache headers的文章。Subclass NSURLCache for Ultimate Control如果你想绕过 
Cache-Control
 需求,定义你自己的规则来读写一个带有 
NSURLResponse
对象的
NSURLCache
,你可以继承 
NSURLCache
。这里有个例子,使用 
CACHE_EXPIRES
 来判断在获取源数据之前对缓存数据保留多长时间。(感谢 Mattt Thompson反馈)
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
@interface CustomURLCache : NSURLCachestatic NSString * const CustomURLCacheExpirationKey = @"CustomURLCacheExpiration";static NSTimeInterval const CustomURLCacheExpirationInterval = 600;@implementation CustomURLCache+ (instancetype)standardURLCache {static CustomURLCache *_standardURLCache = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_standardURLCache = [[CustomURLCache alloc]initWithMemoryCapacity:(2 * 1024 * 1024)diskCapacity:(100 * 1024 * 1024)diskPath:nil];}return _standardURLCache;}#pragma mark - NSURLCache- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {NSCachedURLResponse *cachedResponse = [super cachedResponseForRequest:request];if (cachedResponse) {NSDate* cacheDate = cachedResponse.userInfo[CustomURLCacheExpirationKey];NSDate* cacheExpirationDate = [cacheDate dateByAddingTimeInterval:CustomURLCacheExpirationInterval];if ([cacheExpirationDate compare:[NSDate date]] == NSOrderedAscending) {[self removeCachedResponseForRequest:request];return nil;}}}return cachedResponse;}- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponseforRequest:(NSURLRequest *)request{NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:cachedResponse.userInfo];userInfo[CustomURLCacheExpirationKey] = [NSDate date];NSCachedURLResponse *modifiedCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];[super storeCachedResponse:modifiedCachedResponse forRequest:request];}@end
既然你有了自己的 
NSURLCache
子类,不要忘了在AppDelegate里边初始化并使用它
1234
CustomURLCache *URLCache = [[CustomURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024diskCapacity:100 * 1024 * 1024diskPath:nil];[NSURLCache setSharedURLCache:URLCache];
Overriding the NSURLResponse before caching
-connection:willCacheResponse
代理方法是在被缓存之前用于截断和编辑由
NSURLConnection
创建的
NSURLCacheResponse
的地方。为了编辑
NSURLCacheResponse
,返回一个可变的拷贝,如下(代码来自NSHipster blog):
1234567891011121314151617181920
- (NSCachedURLResponse *)connection:(NSURLConnection *)connectionwillCacheResponse:(NSCachedURLResponse *)cachedResponse {NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];NSMutableData *mutableData = [[cachedResponse data] mutableCopy];NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;// ...return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]data:mutableDatauserInfo:mutableUserInfostoragePolicy:storagePolicy];}// If you do not wish to cache the NSURLCachedResponse, just return nil from the delegate function:- (NSCachedURLResponse *)connection:(NSURLConnection *)connectionwillCacheResponse:(NSCachedURLResponse *)cachedResponse {return nil;}
Disabling NSURLCache不想使用 
NSURLCache
,可以,只需要将内存和磁盘空间容量设为零就可以了
1234
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0diskCapacity:0diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];

总结

我写这篇博客是为了iOS社区贡献一份力,总结了一下我在处理关于 
AFNetworking
缓存相关的问题。我们有个内部App加载了好多图片,导致内存问题以及性能问题。我主要职责就是诊断这个App的缓存行为。在这个研究过程中,我在网上搜索了好多资料并且做了好多调试。然后我总结之后写到了这篇博客中。我希望这篇文章能够为其他人用
AFNetworking
的时候提供帮助,真心希望对你们有用处!原文地址:http://blog.originate.com/blog/2014/02/20/afimagecache-vs-nsurlcache/==================================================================================================================================iOS开发网络篇—数据缓存一、关于同一个URL的多次请求  有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的。    上面的情况会造成以下问题(1)用户流量的浪费(2)程序响应速度不够快解决上面的问题,一般考虑对数据进行缓存。  二、缓存  为了提高程序的响应速度,可以考虑使用缓存(内存缓存\硬盘缓存)    第一次请求数据时,内存缓存中没有数据,硬盘缓存中没有数据。缓存数据的过程  当服务器返回数据时,需要做以下步骤(1)使用服务器的数据(比如解析、显示)(2)将服务器的数据缓存到硬盘(沙盒)此时缓存的情况是:内存缓存中有数据,硬盘缓存中有数据。再次请求数据分为两种情况:(1)如果程序并没有被关闭,一直在运行  那么此时内存缓存中有数据,硬盘缓存中有数据。如果此时再次请求数据,直接使用内存缓存中的数据即可(2)如果程序重新启动  那么此时内存缓存已经消失,没有数据,硬盘缓存依旧存在,还有数据。如果此时再次请求数据,需要读取内存中缓存的数据。提示:从硬盘缓存中读取数据后,内存缓存中又有数据了 三、缓存的实现1.说明:由于GET请求一般用来查询数据,POST请求一般是发大量数据给服务器处理(变动性比较大)因此一般只对GET请求进行缓存,而不对POST请求进行缓存  在iOS中,可以使用NSURLCache类缓存数据  iOS 5之前:只支持内存缓存。从iOS 5开始:同时支持内存缓存和硬盘缓存 2.NSURLCacheiOS中得缓存技术用到了NSURLCache类。缓存原理:一个NSURLRequest对应一个NSCachedURLResponse缓存技术:把缓存的数据都保存到数据库中。 3.NSURLCache的常见用法(1)获得全局缓存对象(没必要手动创建)NSURLCache *cache = [NSURLCache sharedURLCache]; (2)设置内存缓存的最大容量(字节为单位,默认为512KB)- (void)setMemoryCapacity:(NSUInteger)memoryCapacity;(3)设置硬盘缓存的最大容量(字节为单位,默认为10M)- (void)setDiskCapacity:(NSUInteger)diskCapacity;(4)硬盘缓存的位置:沙盒/Library/Caches(5)取得某个请求的缓存- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; (6)清除某个请求的缓存- (void)removeCachedResponseForRequest:(NSURLRequest *)request;(7)清除所有的缓存- (void)removeAllCachedResponses; 4.缓存GET请求  要想对某个GET请求进行数据缓存,非常简单  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];  // 设置缓存策略  request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;  只要设置了缓存策略,系统会自动利用NSURLCache进行数据缓存 5.iOS对NSURLRequest提供了7种缓存策略:(实际上能用的只有4种)NSURLRequestUseProtocolCachePolicy // 默认的缓存策略(取决于协议)NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未实现NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求NSURLRequestReturnCacheDataElseLoad// 有缓存就用缓存,没有缓存就重新请求NSURLRequestReturnCacheDataDontLoad// 有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)NSURLRequestReloadRevalidatingCacheData // 未实现 6.缓存的注意事项缓存的设置需要根据具体的情况考虑,如果请求某个URL的返回数据:  (1)经常更新:不能用缓存!比如股票、彩票数据  (2)一成不变:果断用缓存  (3)偶尔更新:可以定期更改缓存策略 或者 清除缓存提示:如果大量使用缓存,会越积越大,建议定期清除缓存 四、简单的代码示例
 1 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event2 {3     // 1.创建请求4     NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:8080/YYServer/video"];5     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];67     // 2.设置缓存策略(有缓存就用缓存,没有缓存就重新请求)8     request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;910     // 3.发送请求11     [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {12         if (data) {13             NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];1415             NSLog(@"%@", dict);16         }17     }];18 }1920 /**21  // 定期处理缓存22  //    if (缓存没有达到7天) {23  //        request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;24  //    }25  // 获得全局的缓存对象26  NSURLCache *cache = [NSURLCache sharedURLCache];27  //    if (缓存达到7天) {28  //        [cache removeCachedResponseForRequest:request];29  //    }3031  // lastCacheDate = 2014-06-30 11:04:303233  NSCachedURLResponse *response = [cache cachedResponseForRequest:request];34  if (response) {35  NSLog(@"---这个请求已经存在缓存");36  } else {37  NSLog(@"---这个请求没有缓存");38  }39  */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: