19 - SDWebImage SDK 底层02

114 阅读4分钟
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等中,使用它来进行图片缓存

image.png

  • name NSCache的名字
  • countLimit 缓存对象的总数,默认为日 不限制。
  • totalcostLimit 緩存对家的总大小,超出上限会释放足够的内存空间出来,在执行插入操作
  • delegate 緩存的value对象可以实现该 NSDiscardablecontent 协议,当你NSCache释放对象是会执行回调函数,在回调西数里释放value对象申请其他资源。 被标记成purage 会优先清除,但不确定是否一定会被清掉
NSCache 使用

WX20221124-105223@2x.png

如上图运行结果证明:countLimit= 5 ,限制最多放入 5 个对象

WX20221124-105600@2x.png

APP 进入后台,会发生如下情况:

image.png

缓存里面的数据全部被删除了,调用了[NSCache removeAllObjects]方法

当模拟 APP 发出内存警告时会发生如下情况:

image.png

发生内存警告时,会调用-(void)cache:(NSCache *)cache willEvictObject:(id)obj 只是清除了部分缓存数据,这个原因看下面展示。

什么样的情况会清除缳存?

  • 超过 countLimit 限制
  • 超过 totalCostLimit 限制
  • 手动调用 remove 主动清除
  • APP进入后台 removeallobjects
  • 内存警告会按照策略清除缓存
  • 遵循了NSDiscardablecontent协议的(内存警告有时会清除有时不会清除 )
NSCache GNUstep 底层代码

头文件: image.png

/** 所有缓存对象的最大总成本。 */ 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

入口函数:

image.png

驱逐对象函数:

image.png

  • 计算访问平均次数

    • 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 使用当前返回的数据