iOS开发进阶:三方源码解读

2022-01-12  本文已影响0人  高涛同学

一、YYMemoryCache的源码解读

YYMemoryCache是用来做内存管理的类,他支持设置缓存对象的个数、最大占用内存大小、时间等限制来达到较好的存储状态,他内部支持通过LRU淘汰策略来清理低频使用的数据。

1.YYMemoryCache分为两个主体部分:
//通过key来查询一个对象
- (nullable id)objectForKey:(id)key;

//添加一个实体到缓存
- (void)setObject:(nullable id)object forKey:(id)key withCost:(NSUInteger)cost;

//通过key来删除一个缓存实体
- (void)removeObjectForKey:(id)key;

//清理所有的缓存实体
- (void)removeAllObjects;

//通过count、内存大小、时间等条件删除缓存实体
- (void)trimToCount:(NSUInteger)count;
- (void)trimToCost:(NSUInteger)cost;
- (void)trimToAge:(NSTimeInterval)age;
//新插入一个节点到头部
- (void)insertNodeAtHead:(_YYLinkedMapNode *)node;

//将节点移动到头部
- (void)bringNodeToHead:(_YYLinkedMapNode *)node;

//移除一个节点
- (void)removeNode:(_YYLinkedMapNode *)node;

//移除尾节点
- (_YYLinkedMapNode *)removeTailNode;

//移除所有节点
- (void)removeAll;

核心部分是_YYLinkedMap链表,他通过hash表来维护节点的生命周期,根据LRU将最新访问的对象移动/插入到链表的头部,那么响应的不常用的就回跑到链表的末尾,再根据内存限制、个数显示等因素移除的不常用的数据。

2.读取:- (id)objectForKey:(id)key
3.写入:- (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost
4.链表:_YYLinkedMap

1.使用双向链表可以快速的移动节点:假如把第N个节点移动到第1个位置,则只需要操作一次就到位了,时间复杂度为O(1);如果使用数组则需要将1N-1之间的数据都向后移动一位,需要执行N-2次,时间复杂度为O(n)
2.使用双向链表可以快速增删元素:假如删除指定的节点,使用爽链表则直接将删除节点的上一节点的next指针指向当前节点的下一个节点,将当前节点的next节点的prev指针指向当前节点的上一个节点,一次操作完成任务,时间复杂度O(1);如果使用单向链表,在做删除时,无法直接拿到当前节点的上一个节点,只能从头开始遍历,找到当前节点的前一个节点,时间复杂度为O(n)

1._YYLinkedMapNode存入hash表的时候,会对其进行retain操作,所以这里不需要强持有。
2.如果这强持有会造成循环引用:相邻的两个节点A.next = B, B.prev = A,构成循环引用了,在释放的时候必须手动将prev、next指针置为nil,并且在removeAll的时候需要手动将每一个节点的前驱、后续指针置为nil,多了很多操作。

两者功能相近,CFMutableDictionaryRef是基于C的实现,效率更高,而NSMutableDictionary是对CFMutableDictionaryRef的封装。

二、Aspects源码解读

1.Objective-Cruntime
+ (void)hookClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector {
    Class class = classObject;
    // 得到被交换类的实例方法
    Method fromMethod = class_getInstanceMethod(class, fromSelector);
    // 得到交换类的实例方法
    Method toMethod = class_getInstanceMethod(class, toSelector);
    
    // class_addMethod() 函数返回成功表示被交换的方法没实现,然后会通过 class_addMethod() 函数先实现;返回失败则表示被交换方法已存在,可以直接进行 IMP 指针交换 
    if(class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
        // 进行方法的交换
        class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod));
    } else {
        // 交换 IMP 指针
        method_exchangeImplementations(fromMethod, toMethod);
    }
}
2.Aspects
[NXViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info, BOOL animated){
        NSLog(@"NXViewController-viewDidAppear:");
} error:NULL];
上一篇 下一篇

猜你喜欢

热点阅读