iOS 黑魔法 - Method Swizzling实现原理
2021-10-13 本文已影响0人
smile_frank
Method Swizzling
Method Swizzling,顾名思义,就是交换两个 方法的实现。简单来说,就是利用Objective-C Runtime的动态绑定特性,将一个方法的实现与另 一个方法的实现进行交换。
objc_class
在Objective-C的Runtime中,一个类是用一个名为objc_class的 结构体表示的,它的定义如下:
objc_method_list
我们从上述结构体中可以发现一 个objc_method_list指针,它保存着当前类的所有方法列表。同 时,objc_method_list也是一个结构体,它的定义如下:
objc_method
我们从上面的结构体中发现一个objc_method字段,它的定义如下:
我们从上面的结构体中还发现,一个方法由如下三部分组成。
- method_name:方法名。
- method_types:方法类型。
- method_imp:方法实现。
交换原理
使用Method Swizzling交换方法,其实就是修改了objc_method 结构体中的mthod_imp,即改变了method_name和method_imp的映射关系如下:
实现Method Swizzling的相关函数
Method class_getInstanceMethod(Class_Nullable aClass,SEL_Nonnull aSelector) OBJC_AVAILABLE(10.0,2.0,9.0,1.0,2.0);
- 功能:返回目标类aClass、方法名为aSelector 的实例方法。
-
参数说明
- aClass:目标类。
- aSelector:方法名。
注意点
只有当前类以及它的父类均不包含指定 的方法时,才会返回NULL。
BOOL class_addMethod(Class_Nullable aClass,SEL_Nonnull aSelector,IMP_Nonnullimp,const char * _Nullable types) OBJC_AVAILABLE(10.5,2.0,9.0,1.0,2.0);
-
功能:给目标类aClass添加一个新的方法, 同时包括方法的实现。
-
参数说明
- aClass:目标类。
- aSelector:要添加方法的方法名。
- imp:要添加方法的方法实现。
- types:方法实现的编码类型。
注意点
返回成功,说明已经成功在目标类中添 加了该方法;返回失败,说明在目标类中已经存 在相同方法名的方法。
IMP method_getImplementation(Method_Nonnull method) OBJC_AVAILABLE (10.5,2.0,9.0,1.0,2.0);
-
功能:返回方法实现的指针。
-
参数说明
- method:目标方法。
IMP class_replaceMethod(Class_Nullable aClass,SEL_Nonnull aSelector,IMP_Nonnull imp,const char * _Nullable types) OBJC_AVAILABLE(10.5,2.0,9.0,1.0,2.0);
- 功能:替换目标类aClass的aSelector方法的指 针。
-
参数说明
- aClass:目标类。
- aSelector:目前方法的方法名。
- imp:新方法的方法实现。
- types:方法实现的编码类型。
void method_exchangeImplementations(Method_Nonnull m1,Method_Nonnull m2) OBJC_AVAILABLE(10.5,2.0,9.0,1.0,2.0);
- 功能:交换两个方法的实现指针。
-
参数说明
- m1:交换方法1。
- m2:交换方法2
#import <objc/runtime.h>
@implementation NSObject (Swizzler)
+ (BOOL)sensorsdata_swizzleMethod:(SEL)originalSEL withMethod:(SEL)alternateSEL {
//获取原始的方法
Method originalMethod = class_getInstanceMethod(self, originalSEL);
if (!originalMethod) {
return NO;
}
//获取将要交换的方法
Method alternateMethod = class_getInstanceMethod(self, alternateSEL);
if (!alternateMethod) {
return NO;
}
//交互两个方法的实现
method_exchangeImplementations(originalMethod, alternateMethod);
//返回yes,方法交换成功
return YES;
}
@end