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的实现其实就是把缓存对象存储成一个个模型,然后统一在缓存池中根据时间戳排序处理