Swift源码-NSCache

193 阅读2分钟

一.特点

  • 便利性: 类似字典,存取方便.

  • 线程安全

  • 缓存策略: 可设置存储的最大限制.

二.源码分析

主要属性

open class NSCache<KeyType : AnyObject, ObjectType : AnyObject> : NSObject {
    //字典
    private var _entries = Dictionary<NSCacheKey, NSCacheEntry<KeyType, ObjectType>>()
    //锁
    private let _lock = NSLock()
    private var _totalCost = 0
    //链表
    private var _head: NSCacheEntry<KeyType, ObjectType>?
    //存储阈值(淘汰策略)
    open var totalCostLimit: Int = 0 // limits are imprecise/not strict
    open var countLimit: Int = 0 // limits are imprecise/not strict
}

属性作用与特点关系

  • **1. _entries **

负责存取.印证了特点1.

  • **2._lock **

保证了线程安全,例如查询实现,代码如下:

open func object(forKey key: KeyType) -> ObjectType? {
        var object: ObjectType?
        
        let key = NSCacheKey(key)
        
        _lock.lock()
        if let entry = _entries[key] {
            object = entry.value
        }
        _lock.unlock()
        
        return object
    }
  • 3. _head,totalCostLimit,countLimit,totalCost

存储的实现代码如下:

//调用API
open func setObject(_ obj: ObjectType, forKey key: KeyType) {
        setObject(obj, forKey: key, cost: 0)
    }
    //内部实现
    open func setObject(_ obj: ObjectType, forKey key: KeyType, cost g: Int) {
    //cost为obj存储资源大小,默认为0.
        let g = max(g, 0)
        let keyRef = NSCacheKey(key)
        _lock.lock()
        let costDiff: Int
        //检测是否key对应有obj
        //有
        if let entry = _entries[keyRef] {
        //资源大小对比
            costDiff = g - entry.cost
            entry.cost = g
            entry.value = obj
            if costDiff != 0 {
            //先删除再存储
                remove(entry)
                insert(entry)
            }
        } else {
        //无: 直接存储
            let entry = NSCacheEntry(key: key, value: obj, cost: g)
            _entries[keyRef] = entry
            insert(entry)
            costDiff = g
        }
       //缓存处理: 
        _totalCost += costDiff
        //如果totalCostLimit> 0, 如果totalCostLimit超出,则执行删除操作.
        var purgeAmount = (totalCostLimit > 0) ? (_totalCost - totalCostLimit) : 0
        while purgeAmount > 0 {
            if let entry = _head {
                delegate?.cache(unsafeDowncast(self, to:NSCache<AnyObject, AnyObject>.self), willEvictObject: entry.value)
                
                _totalCost -= entry.cost
                purgeAmount -= entry.cost
                
                remove(entry) // _head will be changed to next entry in remove(_:)
                _entries[NSCacheKey(entry.key)] = nil
            } else {
                break
            }
        }
        //类似的,如果countLimit超出,则执行删除操作.
        var purgeCount = (countLimit > 0) ? (_entries.count - countLimit) : 0
        while purgeCount > 0 {
            if let entry = _head {
                delegate?.cache(unsafeDowncast(self, to:NSCache<AnyObject, AnyObject>.self), willEvictObject: entry.value)
                
                _totalCost -= entry.cost
                purgeCount -= 1
                //删除
                remove(entry) // _head will be changed to next entry in remove(_:)
                _entries[NSCacheKey(entry.key)] = nil
            } else {
                break
            }
        }
        
        _lock.unlock()
    }

三.缓存策略

缓存策略太简单,适应不了复杂需求.

四.优秀的缓存策略:

  • 自动计算存储对象的实际容量.
  • 按时间,先清除最早的内容.
  • 按使用频率,先清除使用频率低的内容.