Method Swizzling
是什么
Method Swizzling的含义是方法交换,其主要作用是在运行时将一个方法的实现替换为另一个方法的实现
交换前: 交换后
使用场景 eg:通过 Method Swizzling 替换viewController中的生命周期函数,比如ViewDidAppear,打印一些日志,或者做一些路径上传的操作。
注意事项
- 应该只在+load中执行Method Swizzling。
- Method Swizzling 应该总是在dispatch_once中执行。保证只交换一次。
- 使用Method Swizzling 后要记得调用原来方法的实现。
- 避免命名冲突
- 如果是继承关系的子类中,交换方法的时候,注意判断交换的方法以及被交换的方法是否都已经实现。
eg:
+ (void)lg_bestMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if (!cls) NSLog(@"传入的交换类不能为空");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
if (!oriMethod) { // 避免动作没有意义
// 在oriMethod为nil时,替换后将swizzledSEL复制一个不做任何事的空实现,代码如下:
class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){
NSLog(@"来了一个空的 imp");
}));
}
// 一般交换方法: 交换自己有的方法 -- 走下面 因为自己有意味添加方法失败
// 交换自己没有实现的方法:
// 首先第一步:会先尝试给自己添加要交换的方法 :personInstanceMethod (SEL) -> swiMethod(IMP)
// 然后再将父类的IMP给swizzle personInstanceMethod(imp) -> swizzledSEL
//oriSEL:personInstanceMethod
BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
if (didAddMethod) {
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else{
method_exchangeImplementations(oriMethod, swiMethod);
}
}
load VS initialize
加载时刻
load方法时当一个类或者分类被添加到Objective-C运行时调用, 在load_images时调用
加载顺序
- 类的+load的方法在它的父类+load方法之后调用
- 分类的+load方法在这个类自己的+load方法之后调用
initialize
运行时以线程安全的方式将初始化消息发送给类。也就是说,initialize由第一个线程向类发送消息,其它的线程向这个类发送消息时会被阻塞,直到initialize完成。
加载顺序
每个类只调用Initialize一次。父类先调用然后调用子类
如果子类没有实现initialize,或者子类显示的调用了[super initialize],那么父类可能会被调用多次。
KVC
KVC是一种键值编码技术,相关的方法有valueforkey以及setValueforKey
setValueforKey它的实现逻辑是什么样子的呢
KVC设置值过程
- 判断是否存在
set<key>
或者_set<key>()
,setIs<key>
- 如果没有1
- 2.1:判断
accessInstanceVariblesDirectly
是否返回YES,系统默认YES - 2.2:如果是,判断
_<key>
、_is<key>
、<key>
、is<key>
、等实例变量 - 2.3:直接给这些实例变量赋值
- 如果都没有, 则调用
setValue: forUndefinedKey
报错KVC取值过程
get<key>
、<key>
、is<key>
or_<key>
如果有,则跳转5- 如果1没有,则判断是否为NSArray
- 判断是否为NSSet判断
- 非集合类型判断
- 4.1:
accessInstanceVariblesDirectly
是否返回YES - 4.2:
_<key>
、_is<key>
、<key>
、is<key>
这些实例属性是否有值 - 4.3: 如果找到,直接取值,然后5 5:细节处理
- 5.1:如果检索到的属性值是对象指针,则只返回结果
- 5.2: 如果该值是NSNumber支持的标量,存在NSNumber实例中返回
- 5.3:如果结果是NSNumber不支持的标量类型,则转换为NSValue对象并返回
-
都没有则
valueForUndefinedKey
报错 -
集合类型还需要处理