YYCache 的结构

@interface _YYLinkedMapNode : NSObject {
    @package
    __unsafe_unretained _YYLinkedMapNode *_prev; // retained by dic
    __unsafe_unretained _YYLinkedMapNode *_next; // retained by dic
    id _key;
    id _value;
    NSUInteger _cost;
    NSTimeInterval _time;
}
@end
@implementation _YYLinkedMapNode
@end
/**
 A linked map used by YYMemoryCache.
 It's not thread-safe and does not validate the parameters.
 Typically, you should not use this class directly.
 */
@interface _YYLinkedMap : NSObject {
    @package
    CFMutableDictionaryRef _dic; // do not set object directly
    NSUInteger _totalCost;
    NSUInteger _totalCount;
    _YYLinkedMapNode *_head; // MRU, do not change it directly
    _YYLinkedMapNode *_tail; // LRU, do not change it directly
    BOOL _releaseOnMainThread;
    BOOL _releaseAsynchronously;
}

/// Insert a node at head and update the total cost.
/// Node and node.key should not be nil.
- (void)insertNodeAtHead:(_YYLinkedMapNode *)node;

/// Bring a inner node to header.
/// Node should already inside the dic.
- (void)bringNodeToHead:(_YYLinkedMapNode *)node;

/// Remove a inner node and update the total cost.
/// Node should already inside the dic.
- (void)removeNode:(_YYLinkedMapNode *)node;

/// Remove tail node if exist.
- (_YYLinkedMapNode *)removeTailNode;

/// Remove all node in background queue.
- (void)removeAll;
_YYLinkedMapNode *_prev为该节点的头指针,指向前一个节点
_YYLinkedMapNode *_next为该节点的尾指针,指向下一个节点
头指针和尾指针将一个个子节点串连起来,形成双向链表

核心实现方法:
- (void)bringNodeToHead:(_YYLinkedMapNode *)node {
    if (_head == node) return; // 如果当前节点是链头,则不需要移动
    
    // 链表中存了两个指向链头(_head)和链尾(_tail)的指针,便于链表访问
    if (_tail == node) {
        _tail = node->_prev; // 若当前节点为链尾,则更新链尾指针
        _tail->_next = nil; // 链尾的尾节点这里设置为nil
    } else {
        // 比如:A B C 链表, 将 B拿走,将A C重新联系起来
        node->_next->_prev = node->_prev; // 将node的下一个节点的头指针指向node的上一个节点,
        node->_prev->_next = node->_next; // 将node的上一个节点的尾指针指向node的下一个节点
    }
    node->_next = _head; // 将当前node节点的尾指针指向之前的链头,因为此时node为最新的第一个节点
    node->_prev = nil; // 链头的头节点这里设置为nil
    _head->_prev = node; // 之前的_head将为第二个节点
    _head = node; // 当前node成为新的_head
}
总结:yyCache 是使用了NSdictory + 双向链表来保证数据的最新
AFN
结构
//单个图片存储的数据结构

@interface AFCachedImage : NSObject

 

@property (nonatomic, strong) UIImage *image;

@property (nonatomic, strong) NSString *identifier;

@property (nonatomic, assign) UInt64 totalBytes;

@property (nonatomic, strong) NSDate *lastAccessDate;

@property (nonatomic, assign) UInt64 currentMemoryUsage;

 

@end

//每次获取图片 都会更新时间戳

- (UIImage*)accessImage {

    self.lastAccessDate = [NSDate date];

    return self.image;

 

}

 

//存储的缓存池---缓存的数据 + 当前缓存的内存容量

@interface AFAutoPurgingImageCache ()

@property (nonatomic, strong) NSMutableDictionary <NSString* , AFCachedImage*> *cachedImages;

@property (nonatomic, assign) UInt64 currentMemoryUsage;

@property (nonatomic, strong) dispatch_queue_t synchronizationQueue;

@end

核心实现

如果当前存储的缓存超过设置的阖值就会触发

  if (self.currentMemoryUsage > self.memoryCapacity) {

            UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;

            NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];

            NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"

                                                                           ascending:YES];

            [sortedImages sortUsingDescriptors:@[sortDescriptor]];

 

            UInt64 bytesPurged = 0;

 

            for (AFCachedImage *cachedImage in sortedImages) {

                [self.cachedImages removeObjectForKey:cachedImage.identifier];

                bytesPurged += cachedImage.totalBytes;

                if (bytesPurged >= bytesToPurge) {

                    break ;

                }

            }

            self.currentMemoryUsage -= bytesPurged;

        }

总结:

AFN的实现其实就是把缓存对象存储成一个个模型,然后统一在缓存池中根据时间戳排序处理