__has_include宏的使用

此宏传入一个你想引入文件的名称作为参数,如果该文件能够被引入则返回1,否则返回0.

在导入头文件时,使用__has_include来判断是否可以尖括号引入, AFNetworking库和YYCache库都能见到这种用法,如下:

#if __has_include(<AFNetworking/AFNetworking.h>)
#import <AFNetworking/AFNetworking.h>
#else
#import "AFNetworking.h"
#endif

UNAVAILABLE_ATTRIBUTE宏的作用

在YYCache中,作者使用UNAVAILABLE_ATTRIBUTE来标init和new方法,只保留一个自定义的创建实例方法

- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;

NS_ASSUME_NONNULL_BEGIN的用法

NS_ASSUME_NONNULL_BEGIN配合NS_ASSUME_NONNULL_END使用,使包在中间的属性和方法声明,默认参数类型不允许为空,配合nullable标注允许为空的参数属性.如

NS_ASSUME_NONNULL_BEGIN

@interface YYCache : NSObject
@property (copy, readonly) NSString *name;
@property (strong, readonly,nullable) YYMemoryCache *memoryCache;
- (nullable instancetype)initWithName:(NSString *)name;
@end

NS_ASSUME_NONNULL_END

使用gcd来管理semaphore信号量作锁

创建一个值为1的信号量

dispatch_semaphore_t _lock = dispatch_semaphore_create(1);

需要锁时使用以下方法将值减1为0

dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER)

开锁时使用以下方法将值加1为1

dispatch_semaphore_signal(self->_lock)

其中DISPATCH_TIME_FOREVER代表gcd中的无限时间,对应的可以用以下方法来实现等待两秒

dispatch_semaphore_wait(signal, dispatch_time(DISPATCH_TIME_NOW, (Int64)(NSEC_PER_SEC * 2)))

使用NSMapTable来代替NSDictionary,实现对k,v的内存引用管理

扩展如下

 NSHashTable 或 NSMapTable,分别对应着 NSSet 和 NSDictionary
 
 NSMapTable 是 NSDictionary 的通用版本。和 NSDictionary / NSMutableDictionary 不同的是,NSMapTable 具有下面这些特性:
     * NSDictionary / NSMutableDictionary 对键进行拷贝,对值持有强引用
     * NSMapTable 是可变的,没有不可变的对应版本
     * NSMapTable 可以持有键和值的弱引用,当键或者值当中的一个被释放时,整个这一项就会被移除掉
     * NSMapTable 可以在加入成员时进行 copy 操作
     * NSMapTable 可以存储任意的指针,通过指针来进行相等性和散列检查
 以上:NSMapTable 专注于强引用和弱引用

一个NSMapTable 初始化实例

        _globalInstances = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];

使用递归加GCD延迟调用来定时检测上限

- (void)_trimRecursively {
    __weak typeof(self) _self = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_autoTrimInterval * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        __strong typeof(_self) self = _self;
        if (!self) return;
        [self _trimInBackground];
        [self _trimRecursively];
    });
}

告诉编译器某种情况就不要警告了

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
    return isAppExtension ? nil : [UIApplication performSelector:@selector(sharedApplication)];
#pragma clang diagnostic pop

以上为告知编译器不要警告selector找不到

iOS8之后的新特性-扩展

使用以下方法来判断是否为扩展

 Class cls = NSClassFromString(@"UIApplication");
        if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES;
        if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES;

扩展介绍

使用CFDictionary来保存sqlite3的stmt

使用内联函数提高效率

内联函数可以当作宏来使用,区别如下

当然inline函数与宏有区别,inline可以:

解决函数调用效率的问题:
函数之间调用,是内存地址之间的调用,当函数调用完毕之后还会返回原来函数执行的地址。函数调用有时间开销,内联函数就是为了解决这一问题。
不用inline修饰的函数, 汇编时会出现 call 指令.调用call指令就是就需要:
(1)将下一条指令的所在地址入栈
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序).

YYCache中的内存缓存使用了链表数据结构

定义了一个链表类,并分别使用MRU(Most Recently Used)和LRU(Least Recently Used)维护了两个对象,方便对最常使用和最少使用的数据进行管理

在内存缓存中的锁没有使用信号量,而是使用了pthread_mutex,性能稍弱于信号量,用法简单,类似于Semaphore的value为1

标签: iOS, YYCache, 缓存,

添加新评论