Runtime基础使用场景-拦截替换方法(class_addMethod ,class_replaceMethod和method_exchangeImplementations)
- class_addMethod (添加方法)
- class_replaceMethod (替换方法)
- method_exchangeImplementations (交换方法)
交换方式一
+(void)load{
//获取两个类的方法
Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method m2 = class_getClassMethod([UIImage class], @selector(ll_imageName:));
//开始交换方法实现
method_exchangeImplementations(m1, m2);
}
交换方式二
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ // 保证方法只替换一次
//要特别注意你替换的方法到底是哪个性质的方法
// When swizzling a Instance method, use the following:
// Class class = [self class];
// When swizzling a class method, use the following:
Class class = object_getClass((id)self);
SEL originalSelector = @selector(systemMethod_PrintLog);
SEL swizzledSelector = @selector(ll_imageName);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
说明:
systemMethod_PrintLog:被替换方法ll_imageName:替换方法
class_addMethod:如果发现方法已经存在,会失败返回,也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现
-
1.如果返回成功: 则说明被替换方法没有存在.也就是被替换的方法没有被实现,我们需要先把这个方法实现,然后再执行我们想要的效果,用我们自定义的方法去替换被替换的方法. 这里使用到的是class_replaceMethod这个方法. class_replaceMethod本身会尝试调用class_addMethod和method_setImplementation,所以直接调用class_replaceMethod就可以了)
-
2.如果返回失败:则说明被替换方法已经存在.直接将两个方法的实现交换即
另外:
我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP
我们可以利用 class_replaceMethod 来修改类
我们可以利用 method_setImplementation 来直接设置某个方法的IMP
其实我们如果 研究过 AFN 代码的话,会发现, AFN 就是第二种写法.在AFURLSessionManager.m的第296行:
static inline void af_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
网友评论