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
这样,我们声明了一个2M内存,100M磁盘空间的
既然你有了自己的
Overriding the NSURLResponse before caching
Disabling NSURLCache不想使用
(译)缓存在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从
AFNetworking2.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]; |
NSURLCache。对NSURLRequest对象设置缓存策略
NSURLCache对每个
NSURLRequest对象都会遵守缓存策略(NSURLRequestCachePolicy)。策略定义如下:NSURLRequestUseProtocolCachePolicy:指定定义在协议实现里的缓存逻辑被用于URL请求。这是URL请求的默认策略NSURLRequestReloadIgnoringLocalCacheData:忽略本地缓存,从源加载NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地&服务器缓存,从源加载NSURLRequestReturnCacheDataElseLoad:先从缓存加载,如果没有缓存,从源加载NSURLRequestReturnCacheDataDontLoad离线模式,加载缓存数据(无论是否过期),不从源加载NSURLRequestReloadRevalidatingCacheData存在的缓存数据先确认有效性,无效的话从源加载用NSURLCache缓存到磁盘Cache-Control HTTP Header
Cache-Control或者
Expiresheader 必须在从服务器返回的 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]; |
-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;} |
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 */
相关文章推荐
- iOS --- AFNetworking3.0网络请求方法封装(自带缓存功能)
- AFNetworking3.0网络请求方法封装(自带缓存功能)
- AFNetworking3.0网络请求方法封装(自带缓存功能)
- AFNetworking3.0网络请求方法封装(自带缓存功能)
- AFNetworking网络请求时注意的cookies缓存问题
- AFNetworking3.0网络请求方法封装(自带缓存功能)
- iOS 网络请求(AFNetworking)失败的错误码分析
- 设置AFNetworking网络请求的超时时间
- AFNetworking网络状态判断和网络请求The network connection was lost."问题
- iOS基础8:自定义MyData/自定义SQLite用于网络判断,版本判断,图片缓存处理,下载或者上传的GET或POST请求,加密手段,.数据解析
- iOS 网络请求(POST/GET) 系统、AFNetworking,MKNetwork
- 教你写Android网络框架之请求配置与Response缓存
- Android网络框架之请求配置与Response缓存(四)
- 缓存小姐 挡拆,网络请求 不同步 惹的祸,
- AFNetWorking 网络请求
- AFNetworking 2.0 网络请求封装使用
- QF——网络之网络请求的几种方式,图片缓存
- AFNetworkingErrorDomain 网络请求报错
- ios中网络请求缓存
- ios中使用block回调或代理方式请求网络接口数据(包括网络缓存)