AFNetworking中的缓存是如何工作的?:对AFImageCache & NSUrlCache 解释
来源:互联网 发布:无锡淘宝影视 张飞飞 编辑:程序博客网 时间:2024/06/05 10:31
大致翻译自:How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained
如果你是个在使用Mattt Thompson’s的AFNetworking
的开发者,也许你会好奇或者困惑于缓存的机制和你如何调整它,已对自己有利。 AFNetworking
实际上用了2种不同的缓存机制:
- AFImageCache:
AFNetworking
专用的memory-only图像缓存,继承自NSCache - NSURLCache:
NSURLConnection's
的默认的URL缓存机制,用来存储NSURLResponse
对象:默认是in-memory
缓存,也可以配置为on-disk
的持久化缓存。
为了了解每个缓存系统是怎么工作的,让我们来看看它们是怎么定义的:
AFImageCache是怎样工作的?
AFImageCache
是UIImageView+AFNetworking
类别的一部分。它是NSCache
的子类,把URL字符串作为一个键(从输入的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 *)image forRequest:(NSURLRequest *)request { if (image && request) { [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; }}
AFImageCache
是NSCache
的private implementation。在UIImageView+AFNetworking
类别之外,无法自定义。它将所有的UIImage
对象存储到它的NSCache
中。NSCache
来控制UIImage
对象什么时候被释放。如果你像监测images什么时候可以被释放掉,你可以实现NSCacheDelegate
的cache:willEvictObject
方法。
编辑(03.14.14):Mattt Thompson已通知我,自AFNetworking
2.1,AFImageCache
是可配置的。现在有个公有的方法setSharedImageCache。这是AFN 2.2.1 的说明UIImageView+AFNetworking specification。
NSURLCache是如何工作的?
由于AFNetworking
使用了NSURLConnection
,它充分利用了它原生的缓存机制NSURLCache
。NSURLCache
缓存通过NSURLConnection
返回的的NSURLResponse
对象。
Enabled by Default, but Needs a Hand
NSURLCache
的sharedCache
是默认启用的,被用来获取任何NSURLConnection
对象的URL内容。
不幸的是,it has a tendency to hog memory而且默认配置是不会直接写入到磁盘上。为了tame the beast,并增加可持续性,你可以在app代理中声明一个共享的NSURLCache
,如下:
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024 diskCapacity:100 * 1024 * 1024 diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];
这里我们声明了一个共享的NSURLCache
,占2mb内存,100mb的磁盘空间。
在NSURLRequest对象设置缓存策略
NSURLCache会遵循每个NSURLRequest对象的缓存策略(NSURLRequestCachePolicy)。策略定义如下:
- NSURLRequestUseProtocolCachePolicy:对特定的 URL 请求使用网络协议中实现的缓存逻辑。这是默认的策略。
- NSURLRequestReloadIgnoringLocalCacheData:忽略本地缓存,重新加载
- NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地和远程缓存,重新加载
- NSURLRequestReturnCacheDataElseLoad:无论缓存是否过期,先使用本地缓存数据。如果缓存中没有请求所对应的数据,那么从原始地址加载数据。
- NSURLRequestReturnCacheDataDontLoad:无论缓存是否过期,先使用本地缓存数据。如果缓存中没有请求所对应的数据,那么放弃从原始地址加载数据,请求视为失败(即:“离线”模式)。
- NSURLRequestReloadRevalidatingCacheData:从原始地址确认缓存数据的合法性后,缓存数据就可以使用,否则从原始地址加载。
使用NSURLCache缓存到磁盘上
Cache-Control HTTP Header
为了在客户端缓存,Cache-Control
header或者Expires
heade必须在服务器的HTTP的响应头中(Cache-Control
header存在的优先级高于Expires
header)。有许多情况要考虑到。 Cache Control可以有定义的参数,例如max-age
(在更新响应之前缓存要多久), public / private access,或者是no-cache
无缓存(不缓存响应)。这儿是对HTTP cache headers的简介。
Subclass NSURLCache for Ultimate Control
如果你想要绕过HTTP Cache-Control
header的要求,想要定义你自己的读写给定NSURLResponse
对象的NSURLCache
规则,你可以继承NSURLCache
。
下面一个例子,该例子使用了CACHE_EXPIRES
来标记在重新获取前要持有缓存对象多久:
(感谢Mattt Thompson的反馈和对代码的编辑)
@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 *)cachedResponse forRequest:(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初始化时使用它:
CustomURLCache *URLCache = [[CustomURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024 diskCapacity:100 * 1024 * 1024 diskPath:nil];[NSURLCache setSharedURLCache:URLCache];
在缓存前重写NSURLResponse
在缓存前,NSURLConnection
的-connection:willCacheResponse
代理方法是来拦截和编辑NSURLCachedResponse
的地方。为了编辑NSURLCachedResponse
,如下所示返回可编辑的副本(来自NSHipster blog):
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy]; NSMutableData *mutableData = [[cachedResponse data] mutableCopy]; NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly; // ... return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response] data:mutableData userInfo:mutableUserInfo storagePolicy:storagePolicy];}// If you do not wish to cache the NSURLCachedResponse, just return nil from the delegate function:- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return nil;}
禁用NSURLCache
如果不想使用NSURLCache
呢?若要禁用NSURLCache
,在你的appDelegate中,把共享的NSURLCache
的内存和磁盘空间置为0即可:
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];
总结
我写这篇博客是为了对iOS社区有益,我总结了所有与AFNetworking缓存有关的信息。我们内部有个app来加载大量的图片,它有一些内存和性能问题。我被安排来诊断app的缓存行为。在练习的过程中,我在网上发现了大量的信息,并做了大量的调试和测试。我希望我总结的信息,可以为其他使用AFNetworking的人提供额外的信息。我希望这对你有所帮助。
- AFNetworking中的缓存是如何工作的?:对AFImageCache & NSUrlCache 解释
- 11、缓存在AFNetworking中是如何工作的?AFImageCache和NSUrlCache给你答案
- (译)缓存在AFNetworking中是如何工作的?AFImageCache和NSUrlCache给你答案
- (译)缓存在AFNetworking中是如何工作的?AFImageCache和NSUrlCache给你答案
- (译)缓存在AFNetworking中是如何工作的?AFImageCache和NSUrlCache给你答案
- AFNetWorking是如何进行数据缓存的--之AFImageCache & NSURLCache 详解
- How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained
- How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained
- AFNetworking 配合NSURLCache 本地缓存
- NSURLCache缓存的位置
- 解释下 JavaScript 中 this 是如何工作的。
- NSURLCache缓存
- Java中的注解是如何工作的?
- Java中的注解是如何工作的?
- Java中的注解是如何工作的?
- Java中的注解是如何工作的?
- Java中的注解是如何工作的?
- hibernate中的二级缓存是如何工作的
- 布尔类型探究
- HDU 1164 Eddy's research I.doc
- linux如何检测插入的设备? Kernel, sysfs, udev and dbus 协同工作
- Oracle存储过程的常用知识
- mysql的安装
- AFNetworking中的缓存是如何工作的?:对AFImageCache & NSUrlCache 解释
- MeasureSpec学习 - 转
- android网络编程之——客户端上传信息到网络上面网页(POST)
- 指令系统
- HDU 1215 七夕节
- [读书笔记] 关于Windows的结构化异常处理SEH(一)
- IPad开发之有帮助的开发工具
- string
- GCD介绍(一): 基本概念和Dispatch Queue