NSCache 和 NSURLCache
NSCache 和 NSDictionary区别:
-
NSCache是key-Value数据结构,其中key是强引用,不实现NSCoping协议。 当系统资源抵要耗尽的,NSCache可以自动制减缓存,迎循了LRU(lease recently used)算法,如果是宇典的话,就需要监听didReceiveMemorywarning 然后在手的处理内存警告。
-
NsCache是线程安全的,NSMutableDict ionary是线程不安全的。 开发者可以不编写锁代码的前提下,多线程同时访问NSCache.
-
NsCache可以方便的探控缓存的聯减,使用tota1lcostLinit,countLinit属性可以方便的控制緩存的大小。
-
NSCache对key的要求不高,不需要迎守NSCopying幼议,而NSDictionary的key需要迎守NSCopying协议。
NScache API
- NSCache是苹果官方提供的缓存类,在AFNetworking,SDWebImage等中,使用它来进行图片缓存
- name NSCache的名字
- countLimit 缓存对象的总数,默认为日 不限制。
- totalcostLimit 緩存对家的总大小,超出上限会释放足够的内存空间出来,在执行插入操作
- delegate 緩存的value对象可以实现该 NSDiscardablecontent 协议,当你NSCache释放对象是会执行回调函数,在回调西数里释放value对象申请其他资源。 被标记成purage 会优先清除,但不确定是否一定会被清掉
NSCache 使用
如上图运行结果证明:countLimit= 5 ,限制最多放入 5 个对象
APP 进入后台,会发生如下情况:
缓存里面的数据全部被删除了,调用了[NSCache removeAllObjects]方法
当模拟 APP 发出内存警告时会发生如下情况:
发生内存警告时,会调用-(void)cache:(NSCache *)cache willEvictObject:(id)obj
只是清除了部分缓存数据,这个原因看下面展示。
什么样的情况会清除缳存?
超过 countLimit 限制超过 totalCostLimit 限制手动调用 remove 主动清除APP进入后台 removeallobjects内存警告会按照策略清除缓存遵循了NSDiscardablecontent协议的(内存警告有时会清除有时不会清除 )
NSCache GNUstep 底层代码
头文件:
/** 所有缓存对象的最大总成本。 */ NSUInteger _costLimit;
/** 当前存储对象的总成本。 */ NSUInteger _totalCost;
/** 缓存中的最大对象数。 */ NSUInteger _countLimit;
/** 委托对象,当对象即将被驱逐时得到通知。 */ id _delegate;
/** 指示丢弃的对象是否应该被逐出的标志 */ BOOL _evictsObjectsWithDiscardedContent;
/** 此缓存的名称。 */ NSString *_name;
/** 从名称到此缓存中对象的映射。 */ NSMapTable *_objects;
/** 此缓存中所有潜在可回收对象的 LRU 排序。 */GS_GENERIC_CLASS(NSMutableArray, ValT) *_accesses;
/** 访问对象的总次数 */ int64_t _totalAccesses;
- _evictsObjectsWithDiscardedContent 指示丢弃的对象是否应该被逐出的标志,遵循了遵循了NSDiscardablecontent协议
- _objects 从名称到此缓存中对象的映射,存储数据,数据结构是 NSMapTable
入口函数:
驱逐对象函数:
-
计算访问平均次数
- NSUInteger averageAccesses = ((_totalAccesses / (double)count) * 0.2) + 1;
- 乘以 0.2 是为了驱逐 20%对象,
- 加 1 是为平均访问次数>0
-
拿到需要驱逐的对象
- _accesses 对象是此缓存中所有潜在可回收对象的 LRU 排序。
- NSEnumerator *e = [_accesses objectEnumerator];
-
对象的访问次数小于平均访问次数,并且被标记了是可以驱逐的
- 不要清除经常访问的对象,此时用了 LFU
- Don't evict frequently accessed objects.
if(obj->accessCount < averageAccesses && obj->isEvictable) { [obj->object discardContentIfPossible]; // 当前对象被编辑,则丢弃 if ([obj->object isContentDiscarded]) //当前对象丢弃了,则返回野生 { } }NSMapTable 中的对象存储的是以下结构:
@interface _GSCachedObject : NSObject { @public id object; NSString *key; int accessCount;//LFU Least Frequently Used 访问次数 NSUInteger cost; BOOL isEvictable; } @end- lru 最近最少使用,强调时间,最长未使用的拖被清除掉
- lfu 最近最少次数使用 ,最近一段时间内,使用的次数最少
NSCache 使用方便,类似于字典
NSCache 线程安全
NSCache 能释放存储对象
NSCache 的key不会被拷贝,不需要实现Copying协议 ---- NSMapTable
NSCache 的淘汰策略 LFU & LRU 两者结合的
NSUrlCache
-
NSURLCache探究
- 网络请求的时候,Get请求
- Cache-Control
max-age 缓存时间 public 谁都可以缓存 private 只有客户端缓存,中间代理无法缓存 no-cache 服务端进行确认 no-store= 禁止使用缓存 - 内存缓存、磁盘缓存
- 沙盒路径当中 response receive_data request
- NSURLSessionConfiguration
- useProtocalCachePolicy - HTTP
- reloadIgnoringLocalCacheData
- returnCacheDataElseLoad
- returnCacheDataDontLoad
- Etag、Last-Modified 当前的资源是否发生改变 从缓存当中取出使用
-
如何处理NSURLCache?
- 默认的缓存策略
客户端发起一个请求 检查本地的缓存 如果没有过期 直接使用缓存数据 如果过期了 对比服务器资源 304 使用缓存数据 200 使用当前返回的数据