博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS AFNetworking 数据缓存
阅读量:5978 次
发布时间:2019-06-20

本文共 10399 字,大约阅读时间需要 34 分钟。

How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained

FEB 20TH, 2014

If you are an iOS developer using   ‘delightful networking framework’  (and if you aren’t, what are you waiting for?), perhaps you have been been curious or confused about the caching mechanism employed and how you can tweak it to your advantage.

 actually takes advantage of 2 separate caching mechanisms:

  • AFImagecache: a memory-only image cache private to , subclassed off of 

  • NSURLCache:  default URL caching mechanism, used to store  objects : an in-memory cache by default, configurable as an on-disk persistent cache

In order to understand how each caching system works, let’s look at how they are defined:

How AFImageCache Works

AFImageCache is a part of the UIImageView+AFNetworking . It is a subclass of , storing  objects with a URL string as its key (obtained from an input  object).

AFImageCache definition:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
@interface AFImageCache : NSCache 
// singleton instantiation :+ (id
)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 is a private implementation of . There is no customization that you can do outside of editing the implementation in the the UIImageView+AFNetworking , directly. It stores all accessed  objects into its . The  controls when the objects are released. If you wish to observe when images are released, you can implement ’s cache:willEvictObject method.

Edit (03.14.14) :  has gratiously  that as of  2.1, AFImageCache is configurable. There is now a public  method. Here’s the full AFN 2.2.1 .

How NSURLCache Works

Since  uses , it takes advantage of its native caching mechanism, .  caches objects returned by server calls via .

Enabled by Default, but Needs a Hand

An  sharedCache is enabled by default and will be used by any  objects fetching URL contents for you.

Unfortunately, it has a tendency to hog memory and does not write to disk in its default configuration. To tame the beast and potentially add some persistance, you can simply declare a shared  in your app delegate like so:

1234
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024                                              diskCapacity:100 * 1024 * 1024                                              diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];

Here we declare a shared  with 2mb of memory and 100mb of disk space

Setting the Cache Policy on NSURLRequest Objects

 will respect the caching policy () of each  object. The policies are defined as follows :

  • NSURLRequestUseProtocolCachePolicy: specifies that the caching logic defined in the protocol implementation, if any, is used for a particular URL load request. This is the default policy for URL load requests

  • NSURLRequestReloadIgnoringLocalCacheData: ignore the local cache, reload from source

  • NSURLRequestReloadIgnoringLocalAndRemoteCacheData: ignore local & remote caches, reload from source

  • NSURLRequestReturnCacheDataElseLoad: load from cache, else go to source.

  • NSURLRequestReturnCacheDataDontLoad: offline mode, load cache data regardless of expiration, do not go to source

  • NSURLRequestReloadRevalidatingCacheData: existing cache data may be used provided the origin source confirms its validity, otherwise the URL is loaded from the origin source.

Caching to Disk with NSURLCache

Cache-Control HTTP Header

Either the Cache-Control header or the Expires header MUST be in the HTTP response header from the server in order for the client to cache it (with the existence of the Cache-Control header taking precedence over the Expires header). This is a huge gotcha to watch out for. Cache Control can have parameters defined such as max-age (how long to cache before updating response), public / private access, or no-cache (don’t cache response).  is a good introduction to HTTP cache headers.

Subclass NSURLCache for Ultimate Control

If you would like to bypass the requirement for a Cache-Control HTTP header and want to define your own rules for writing and reading the  given an  object, you can subclass .

Here is an example that uses a CACHE_EXPIRES value to judge how long to hold on to the cached response before going back to the source:

(Thanks to  for the  and code edits!)

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 *)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

Now that you have your  subclass, don’t forget to initialize it in your AppDelegate in order to use it :

1234
CustomURLCache *URLCache = [[CustomURLCache alloc] initWithMemoryCapacity:2 * 1024 * 1024                                                   diskCapacity:100 * 1024 * 1024                                                                 diskPath:nil];[NSURLCache setSharedURLCache:URLCache];

Overriding the NSURLResponse before caching

The -connection:willCacheResponse delegate is a place to intercept and edit the NSURLCachedResponse object created by NSURLConnection before it is cached. In order to edit the NSURLCachedResponse, return an edited mutable copy as follows (code from ):

1234567891011121314151617181920
- (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;}

Disabling NSURLCache

Don’t want to use the ? Not Impressed? That’s okay. To disable the , simply zero out memory and disk space in the shared  definition in your appDelegate:

1234
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0                                              diskCapacity:0                                              diskPath:nil];[NSURLCache setSharedURLCache:sharedCache];

Summary

I wanted to write this blog post for the benefit of the iOS community, to summarize all of the information I found dealing with caching releated to . We had an internal app loading a lot of images that had some memory issues and performance problems. I was tasked with trying to diagnose the caching behavior of the app. During this exercise, I discovered the information on this post through scouring the web and doing plenty of debugging and logging. It is my hope that this post summarizes my findings and provides an opportunity for others with  experience to add additional information. I hope that you have found this helpful.

转载地址:http://xepox.baihongyu.com/

你可能感兴趣的文章
ServletContextListener使用详解
查看>>
MUI开发记录——我的考勤
查看>>
六、CentOS 6.5 下Nginx的配置
查看>>
小程序循环多个picker选择器,实现动态增、减
查看>>
FasterRCNN原理(转)
查看>>
IIS部署项目
查看>>
前端项目课程4 如何快速布局网页后台
查看>>
【转】如何判断ARP欺骗?该怎么防护?
查看>>
Linux 题目收集
查看>>
Linux 包管理
查看>>
CAP 定理的含义
查看>>
Linq To Sql 项目从Beta迁移到RTM注意事项
查看>>
ASP.NET Atlas简单控件介绍——InputControl,TextBox,Button和CheckBox
查看>>
LINUX下J2SDK安装配置指南
查看>>
[转]Android应用开发提高系列(5)——Android动态加载(下)——加载已安装APK中的类和资源...
查看>>
C#异常处理-关键字finally的使用
查看>>
shell下root用户切换其他用户运行程序
查看>>
CoreData (四)备
查看>>
Linux挂在ntfs格式的U盘
查看>>
'cl.exe' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
查看>>