class_addMethod官方文档如下:
/**
* Adds a new method to a class with a given name and implementation.
*
* @param cls The class to which to add a method.
* @param name A selector that specifies the name of the method being added.
* @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
* @param types An array of characters that describe the types of the arguments to the method.
*
* @return YES if the method was added successfully, otherwise NO
* (for example, the class already contains a method implementation with that name).
*
* @note class_addMethod will add an override of a superclass's implementation,
* but will not replace an existing implementation in this class.
* To change an existing implementation, use method_setImplementation.
*/
OBJC_EXPORT BOOL
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
描述就是:给一个类添加一个新的方法和该方法的具体实现
BOOL: 返回值,YES:方法添加成功 ;NO:方法添加失败
参数:
1、Class cls
cls :要添加新方法的那个类;
传的类型 [类名 class]
实例方法,传入CLass;类方法,传入MetaClss;可以这样理解,OC里的Class里的加号方法,相当于该类的MetalClas的实例方法,类调用类方法,和对象调用实例方法,其实底层实现都是一样的。类也是对象。
2、SEL name
name :要添加的方法名;
添加的方法在本类里面叫的名字,但是方法的格式一定要和你需要添加的方法的格式一样,比如有无参数
传的类型 @selector(方法名)
3、IMP imp
实现这个方法的函数
imp:指向实现方法的指针 就是要添加的方法的实现部分
IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP。这里需要的是IMP,所以不能直接写方法,需要用到一个方法:class_getMethodImplementation
SEL就是一个函数的声明方法,而IMP就是这个方法的实现,也就是一个函数的指针
传的类型
(1)C语言写法:(IMP)方法名 ,举例如下:
不带参数:
//C语言函数
void startEngine(id self, SEL _cmd) {
NSLog(@"my car starts the engine");
}
这是一个 C 语言的函数,它至少包含了 self 和 _cmd 两个参数(self 代表着函数本身,而 _cmd 则是一个 SEL 数据体,包含了具体的方法地址)。如果要在这个方法中新增参数如下
带参数:
//C语言函数
void startEngine(id self, SEL _cmd, NSString *brand) {
NSLog(@"my %@ car starts the engine", brand);
}
@implementation Car (myCar)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(drive)) {
class_addMethod([self class], sel, (IMP)startEngine, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
只要在那两个必须的参数之后添加所需要的参数和类型就可以了,返回值同理,只要把方法名之前的 void 修改成我们想要的返回类型即可
(2)OC的写法:class_getMethodImplementation(self,@selector(方法名:)){ };如下:
OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
这个方法也是runtime的方法,就是获得对应的方法的指针,也就是IMP。
OC写法举例如下:
@implementation Car (myCar)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(drive)) {
class_addMethod([self class], sel, class_getMethodImplementation(self, @selector(startEngine:)), "s@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
- (void)startEngine:(NSString *)brand {
NSLog(@"my %@ car starts the engine", brand);
}
@end
4、const char *types
要添加的方法的返回值和参数 叫 type encodings ;这里可以参考苹果官方文档Type Encodings
"v@:@":v:是添加方法无返回值 @表示是id(也就是要添加的类) :表示添加的方法类型 @表示:参数类型
比如:”v@:”意思就是这已是一个void类型的方法,没有参数传入。
再比如 “i@:”就是说这是一个int类型的方法,没有参数传入。
再再比如”i@:@”就是说这是一个int类型的方法,有一个参数传入。
const char *types含义表如下:
注意点:
用这个方法添加的方法是无法直接调用的,必须用performSelector:调用。
因为performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。
参考文章:
如何实现类方法“ + (BOOL)resolveClassMethod:(SEL) sel”
iOS Runntime 动态添加类方法并调用-class_addMethod