Person类
#import <Foundation/Foundation.h>
@protocol RuntimeBaseProtocol <NSObject>
@optional
- (void)doBaseAction;
@end
@protocol RuntimeProtocol <NSObject,RuntimeBaseProtocol>
@optional
- (void)doOptionalAction;
@end
@interface Person : NSObject<RuntimeProtocol>
@property(nonatomic,copy,nullable)NSString *age;
- (void)name;
- (void)sex;
- (void)name:(NSString *)name sex:(NSString *)sex;
+ (void)personTest;
@end
#import "Person.h"
@implementation Person
- (void)name{
NSLog(@"name is Person ");
}
- (void)sex{
NSLog(@"sex is X ");
}
- (void)name:(NSString *)name sex:(NSString *)sex {
NSLog(@"name is %@, sex is %@ ",name,sex);
}
+ (void)personTest {
NSLog(@"---类方法");
}
@end
Boy类
#import "Person.h"
@interface Boy : Person
@end
#import "Boy.h"
@implementation Boy
@end
UIControl类别
#import <UIKit/UIKit.h>
@interface UIControl (Event)
@property(nonatomic,assign) NSTimeInterval acceptEventInterval;
@property(nonatomic)BOOL ignoreEvent;
@end
// -------------------------------------- //
#import "UIControl+Event.h"
#import <objc/runtime.h>
static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
static const char *UIControl_ignoreEvent = "UIControl_ignoreEvent";
@implementation UIControl (Event)
/**
* 动态添加两个属性
*
*/
- (void)setAcceptEventInterval:(NSTimeInterval)acceptEventInterval
{
objc_setAssociatedObject(self,UIControl_acceptEventInterval, @(acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSTimeInterval)acceptEventInterval {
return[objc_getAssociatedObject(self,UIControl_acceptEventInterval) doubleValue];
}
-(void)setIgnoreEvent:(BOOL)ignoreEvent{
objc_setAssociatedObject(self,UIControl_ignoreEvent, @(ignoreEvent), OBJC_ASSOCIATION_ASSIGN);
}
-(BOOL)ignoreEvent{
return[objc_getAssociatedObject(self,UIControl_ignoreEvent) boolValue];
}
/**
* 交换点击事件的方法
*/
+(void)load {
Method old = class_getInstanceMethod(self,@selector(sendAction:to:forEvent:));
Method new = class_getInstanceMethod(self,@selector(_sendAction:to:forEvent:));
BOOL didAddMethod = class_addMethod(self, @selector(sendAction:to:forEvent:), method_getImplementation(new), method_getTypeEncoding(new));
if (didAddMethod) {
class_replaceMethod(self, @selector(_sendAction:to:forEvent:), method_getImplementation(old), method_getTypeEncoding(old));
}
else {
method_exchangeImplementations(old, new);
}
}
- (void)_sendAction:(SEL)action to:(id)target forEvent:(UIEvent*)event
{
if(self.ignoreEvent)return;
if(self.acceptEventInterval>0)
{
self.ignoreEvent=YES;
[self performSelector:@selector(setIgnoreEventWithNo) withObject:nil afterDelay:self.acceptEventInterval];
}
[self _sendAction:action to:target forEvent:event];
}
-(void)setIgnoreEventWithNo{
self.ignoreEvent=NO;
}
@end
调试类
#import "ViewController.h"
#import "Person.h"
#import "Boy.h"
#import "SignatureModel.h"
#import "UIControl+Event.h"
#import <objc/runtime.h>
#import <objc/message.h>
@interface ViewController ()
@property (nonatomic, strong) UIButton *oneBtn;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"\n\n----------- 添加方法 -----------");
[self addMethod];
NSLog(@"\n\n--------- 发送消息 ----------");
[self objcMsgSend];
NSLog(@"\n\n----------- 替换方法 -----------");
[self exchangeChildMethod];
[self exchangeMethod];
NSLog(@"\n\n----------- person的属性 -----------");
[self printPerson];
NSLog(@"\n\n----------- NSInvocation用法 -----------");
[self signatureInvocation];
NSLog(@"\n\n----------- 点击时间延迟 -----------");
[self addButtonTime];
NSLog(@"\n\n----------- 动态类 -----------");
[self allocClass];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
/**
* 添加方法
*/
- (void)addMethod {
Person *p = [[Person alloc]init];
class_addMethod([Person class], @selector(testParam:), class_getMethodImplementation([ViewController class], @selector(addParam:)), "v@:@");
[p performSelector:@selector(testParam:) withObject:@"传入参数"];
class_addMethod([Person class], @selector(test), class_getMethodImplementation([ViewController class], @selector(add)), "v@:");
[p performSelector:@selector(test)];
class_addMethod([Person class], @selector(testParamBack:), class_getMethodImplementation([ViewController class], @selector(addParamBack:)), "s@:@");
NSString *back = [p performSelector:@selector(testParamBack:) withObject:@33];
NSLog(@"--back: %@",back);
class_addMethod([Person class], @selector(testCC:), (IMP)addCC, "v@:@");
[p performSelector:@selector(testCC:) withObject:@"123"];
//严谨
swizzleMethod([self class], @selector(testAction), @selector(addAction));
[self performSelector:@selector(testAction)];
}
/**
*
* 发送消息
*/
- (void)objcMsgSend {
Person *aObject = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
[aObject name];
// 实例方法调用
((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("testAction"));
// 类方法调用
((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("personTest"));
// 多个参数
void (*glt_msgsend)(id, SEL, NSString *, NSString *) = (void (*)(id, SEL, NSString *, NSString *))objc_msgSend;
glt_msgsend(aObject, @selector(name:sex:), @"JK",@"M");
}
/**
* 方法交换
*/
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear: animated];
NSLog(@"viewWillAppear");
}
- (void)occ_viewWillAppear {
NSLog(@"occ_viewWillAppear");
}
- (void)exchangeMethod{
Method old = class_getInstanceMethod([ViewController class], @selector(viewWillAppear:));
Method new = class_getInstanceMethod([ViewController class], @selector(occ_viewWillAppear));
BOOL didAddMethod = class_addMethod([self class], @selector(viewWillAppear:), method_getImplementation(new), method_getTypeEncoding(new));
// the method doesn’t exist and we just added one
if (didAddMethod) {
class_replaceMethod([self class], @selector(occ_viewWillAppear), method_getImplementation(old), method_getTypeEncoding(old));
}
else {
method_exchangeImplementations(old, new);
}
}
/**
* 替换子类方法
*/
- (void)exchangeChildMethod {
/**
* ⚠️⚠️⚠️❌❌❌
* 如果Boy类里没有复写父类的name方法,
* 此时直接用交换方法,会把父类的name方法替换
*/
Person *p = [[Person alloc]init];
Boy *s = [[Boy alloc]init];
[p name]; //name is Person
[p sex]; //sex is X
Method origMethod = class_getInstanceMethod([Boy class], @selector(name));
Method overrideMethod = class_getInstanceMethod([self class], @selector(sonName));
method_exchangeImplementations(origMethod,overrideMethod);
[s name];//--- son name
[p name];//--- son name
/**✅✅✅
* 如果Boy类里没有复写父类的name方法,
* 用class_addMethod判断Boy类中是否有这个方法,
* didAddMethod: yes 表示Boy类中原先没有,现在添加成功,在class_replaceMethod一下,
* didAddMethod: no 表示Boy类中有,直接交换
*/
Method origMethod2 = class_getInstanceMethod([Boy class], @selector(sex));
Method overrideMethod2 = class_getInstanceMethod([self class], @selector(sonSex));
BOOL didAddMethod = class_addMethod([Boy class], @selector(sex), method_getImplementation(overrideMethod2), method_getTypeEncoding(overrideMethod2));
if (didAddMethod) {
class_replaceMethod([Boy class], @selector(sonSex), method_getImplementation(origMethod2), method_getTypeEncoding(origMethod2));
}
else {
method_exchangeImplementations(origMethod2, overrideMethod2);
}
[s sex];//--- son sex
[p sex];//sex is X
}
- (void)sonName {
NSLog(@"--- son name");
}
- (void)sonSex {
NSLog(@"--- son sex");
}
/**
* 输出一些person的属性
*/
- (void)printPerson{
NSLog(@"\n\n\n---------------获取成员变量列表-----------------");
unsigned int count;
//ivar
Ivar *ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i ++) {
Ivar ivar = ivars[i];
NSLog(@"ivar === %s",ivar_getName(ivar));
}
NSLog(@"\n\n\n--------------方法列表------------------");
Method *methods = class_copyMethodList([Person class], &count);
for (int i = 0; i < count; i ++) {
Method method = methods[i];
NSLog(@"method == %s",method_getName(method));
}
NSLog(@"\n\n\n--------------属性列表------------------");
objc_property_t *propertys = class_copyPropertyList([Person class], &count);
for (int i = 0; i < count; i ++) {
objc_property_t property = propertys[i];
NSLog(@"property === %s",property_getName(property));
}
NSLog(@"\n\n\n--------------协议列表------------------");
Protocol * __unsafe_unretained *protocolList = class_copyProtocolList([_person class],&count);
for (int i = 0; i < count; i++) {
Protocol *protocol = protocolList[i];
NSLog(@"%s",protocol_getName(protocol));
}
//获取类中指定名称实例成员变量的信息
Ivar ivar = class_getInstanceVariable([Person class],"_age");
// 获取成员变量类型编码, 获取成员变量名
NSLog(@"\n\n%s%s%s",__func__,ivar_getTypeEncoding(ivar),ivar_getName(ivar));
// 类实例是否响应指定的selector
BOOL flag = class_respondsToSelector([Person class], @selector(name:sex:));
//获取类制定方法的信息
Method method = class_getInstanceMethod([Person class], @selector(name:sex:));
NSLog(@"%s",sel_getName(method_getName(method)));
//获取类方法的信息
Method method2 = class_getClassMethod([Person class], @selector(personTest));
NSLog(@"%s %u",sel_getName(method_getName(method2)) ,method_getNumberOfArguments(method2));
//获取属性的信息
objc_property_t property = class_getProperty([self class],"person");
NSLog(@"%s %s",property_getName(property) ,property_getAttributes(property));
//获取属性的特性列表
unsigned int outCount;
objc_property_attribute_t *objc_property_attributes = property_copyAttributeList(property,&outCount);
for (int i = 0; i < outCount; i++) {
objc_property_attribute_t objc_property_attribute = objc_property_attributes[i];
NSLog(@"%s %s",objc_property_attribute.name,property_copyAttributeValue(property,objc_property_attribute.name));
}
//获取方法具体实现
IMP imp = class_getMethodImplementation([Person class], @selector(name:sex:));
/**
* 添加属性
*
* class 类
* name 属性名
* attributes 参数
* attributeCount 参数数量
*/
objc_property_attribute_t type = { "T", "@\"NSString\"" };
objc_property_attribute_t ownership = { "&", "N" }; // C = copy
objc_property_attribute_t backingivar = { "V", "" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
if (class_addProperty([Person class], "country", attrs, 3)) {
NSLog(@"%sadd Property success",__func__);
}else{
NSLog(@"%sadd Property fail",__func__);
}
}
- (void)addParam:(NSString *)str{
NSLog(@"----- %@",str);
}
- (void)add{
NSLog(@"----- test");
}
- (NSString *)addParamBack:(NSInteger)a{
NSLog(@"----- paramBack: %li",(long)a);
return @"occ_";
}
- (void)addAction {
NSLog(@"occ_addAction");
}
//C 写法
void addCC(id self, SEL _cmd, NSString *name) {
NSLog(@"occ_ add name %@", name);
}
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
{
// the method might not exist in the class, but in its superclass
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// class_addMethod will fail if original method already exists
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
// the method doesn’t exist and we just added one
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (void)signatureInvocation {
SignatureModel *signatureModel = [[SignatureModel alloc] init];
SEL myMethod = @selector(myLog);
SEL myMethod2 = @selector(myLog:param:parm:);
// 创建一个函数签名,这个签名可以是任意的,但需要注意,签名函数的参数数量要和调用的一致。
NSMethodSignature *sig = [[SignatureModel class] instanceMethodSignatureForSelector:myMethod];
NSMethodSignature *sig2 = [[SignatureModel class] instanceMethodSignatureForSelector:myMethod2];
// 通过签名初始化
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
NSInvocation *invocation2 = [NSInvocation invocationWithMethodSignature:sig2];
//注意:target不要设置成局部变量
invocation.target = signatureModel;
invocation2.target = signatureModel;
// 设置selector
[invocation setSelector:myMethod];
[invocation2 setSelector:myMethod2];
int a = 1, b = 2, c = 3;
// 注意:1、这里设置参数的Index 需要从2开始,因为前两个被selector和target占用。
[invocation2 setArgument:&a atIndex:2];
[invocation2 setArgument:&b atIndex:3];
[invocation2 setArgument:&c atIndex:4];
//将c的值设置为返回值
[invocation2 setReturnValue:&c];
int d;
// 取这个返回值
[invocation2 getReturnValue:&d];
NSLog(@"d:%d", d);
//调用方法
[invocation invoke];
//[invocation2 invoke];
[invocation2 invokeWithTarget:signatureModel];
// 获取参数个数
NSInteger count = sig2.numberOfArguments;
// 打印所有参数类型,
// 这里打印的结果是 @ : i i i 它们是Objective-C类型编码
// @ 表示 NSObject* 或 id 类型
// : 表示 SEL 类型
// i 表示 int 类型
for (int i = 0; i < (int)count; i++) {
const char *argTybe = [sig2 getArgumentTypeAtIndex:i];
NSLog(@"参数类型 %s",argTybe);
}
// 获取返回值的类型
const char *returnType = [sig2 methodReturnType];
NSLog(@"返回值的类型 %s",returnType);
}
/**
* 点击时间连续点击间隔处理
*
*/
- (void)addButtonTime {
_oneBtn =[[UIButton alloc]initWithFrame:CGRectMake(100,100,150,40)];
[_oneBtn setTitle:@"点击时间间隔"forState:UIControlStateNormal];
[_oneBtn setTitleColor:[UIColor redColor]forState:UIControlStateNormal];
_oneBtn.acceptEventInterval =3;
[self.view addSubview:_oneBtn];
[_oneBtn addTarget:self action:@selector(btnEvent)forControlEvents:UIControlEventTouchUpInside];
}
- (void)btnEvent {
NSLog(@"-- 测试间隔");
}
/**
* 动态创建类
* objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
* 添加类 superclass 类是父类 name 类的名字 size_t 类占的空间
* void objc_disposeClassPair(Class cls) 销毁类
* void objc_registerClassPair(Class cls) 注册类
*/
- (void)allocClass{
const char * className = "TestClass";
//要保证全局唯一,key与关联的对象是一一对应关系。必须全局唯一
static const char *TestClass_nameIvar = "nameIvar";
Class kclass = objc_getClass(className);
if (!kclass) {
kclass = objc_allocateClassPair(NSClassFromString(@"UIViewController"), className, 0);
}
/**
* 添加属性
*
* class 类
* name 属性名
* attributes 参数
* attributeCount 参数数量
*/
objc_property_attribute_t type = {"T", "@\"NSString\""};
objc_property_attribute_t ownership = { "C", "" };
objc_property_attribute_t backingivar = { "V", ""};
objc_property_attribute_t attrs[] = {type, ownership, backingivar};
bool success = class_addProperty(kclass, TestClass_nameIvar, attrs, 3);
if (success) {
NSLog(@"addIvar success");
//这个判断不成功???
if (class_isMetaClass(kclass)) {
NSLog(@"是一个类");
}
}
// 向这个类添加一个实例变量
const char *height = "height";
class_addIvar(kclass, height, sizeof(id), rint(log2(sizeof(id))), @encode(id));
objc_registerClassPair(kclass);
if (kclass)
{
id instance = [[kclass alloc] init];
//给变量赋值
objc_setAssociatedObject(instance,TestClass_nameIvar, @"123str", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[instance setValue:@15 forKey:[NSString stringWithUTF8String:height]];
//取值
id nameValue = objc_getAssociatedObject(instance, TestClass_nameIvar);
NSLog(@"-- nameValue: %@",nameValue);
// @encode(type)返回的是type的类型(用C语言 char *的表示)
NSLog(@"instance height = %@", [instance valueForKey:[NSString stringWithUTF8String:height]]);
}
}
@end
2018-03-05 16:42:16.069554+0800 AddMethodDemo[33380:3256539]
----------- 添加方法 -----------
2018-03-05 16:42:16.069790+0800 AddMethodDemo[33380:3256539] ----- 传入参数
2018-03-05 16:42:16.069974+0800 AddMethodDemo[33380:3256539] ----- test
2018-03-05 16:42:16.070233+0800 AddMethodDemo[33380:3256539] ----- paramBack: -5764607523034234350
2018-03-05 16:42:16.070370+0800 AddMethodDemo[33380:3256539] --back: occ_
2018-03-05 16:42:16.070563+0800 AddMethodDemo[33380:3256539] occ_ add name 123
2018-03-05 16:42:16.070747+0800 AddMethodDemo[33380:3256539] occ_addAction
2018-03-05 16:42:16.070878+0800 AddMethodDemo[33380:3256539]
--------- 发送消息 ----------
2018-03-05 16:42:16.071004+0800 AddMethodDemo[33380:3256539] name is Person
2018-03-05 16:42:16.071110+0800 AddMethodDemo[33380:3256539] occ_addAction
2018-03-05 16:42:16.071239+0800 AddMethodDemo[33380:3256539] ---类方法
2018-03-05 16:42:16.071346+0800 AddMethodDemo[33380:3256539] name is JK, sex is M
2018-03-05 16:42:16.071441+0800 AddMethodDemo[33380:3256539]
----------- 替换方法 -----------
2018-03-05 16:42:16.071643+0800 AddMethodDemo[33380:3256539] name is Person
2018-03-05 16:42:16.071804+0800 AddMethodDemo[33380:3256539] sex is X
2018-03-05 16:42:16.073290+0800 AddMethodDemo[33380:3256539] --- son name
2018-03-05 16:42:16.073445+0800 AddMethodDemo[33380:3256539] --- son name
2018-03-05 16:42:16.073559+0800 AddMethodDemo[33380:3256539] --- son sex
2018-03-05 16:42:16.073670+0800 AddMethodDemo[33380:3256539] sex is X
2018-03-05 16:42:16.073977+0800 AddMethodDemo[33380:3256539]
----------- person的属性 -----------
2018-03-06 15:07:35.029363+0800 AddMethodDemo[41943:3974856]
---------------获取成员变量列表-----------------
2018-03-06 15:07:35.029478+0800 AddMethodDemo[41943:3974856] ivar === _age
2018-03-06 15:07:35.029596+0800 AddMethodDemo[41943:3974856]
--------------方法列表------------------
2018-03-06 15:07:35.029713+0800 AddMethodDemo[41943:3974856] method == testCC:
2018-03-06 15:07:35.029917+0800 AddMethodDemo[41943:3974856] method == testParamBack:
2018-03-06 15:07:35.030111+0800 AddMethodDemo[41943:3974856] method == test
2018-03-06 15:07:35.030216+0800 AddMethodDemo[41943:3974856] method == testParam:
2018-03-06 15:07:35.030440+0800 AddMethodDemo[41943:3974856] method == name:sex:
2018-03-06 15:07:35.030679+0800 AddMethodDemo[41943:3974856] method == sex
2018-03-06 15:07:35.031035+0800 AddMethodDemo[41943:3974856] method == .cxx_destruct
2018-03-06 15:07:35.031283+0800 AddMethodDemo[41943:3974856] method == name
2018-03-06 15:07:35.031507+0800 AddMethodDemo[41943:3974856] method == setAge:
2018-03-06 15:07:35.031683+0800 AddMethodDemo[41943:3974856] method == age
2018-03-06 15:07:35.031864+0800 AddMethodDemo[41943:3974856]
--------------属性列表------------------
2018-03-06 15:07:35.032175+0800 AddMethodDemo[41943:3974856] property === age
2018-03-06 15:07:35.032486+0800 AddMethodDemo[41943:3974856] property === hash
2018-03-06 15:07:35.032645+0800 AddMethodDemo[41943:3974856] property === superclass
2018-03-06 15:07:35.032855+0800 AddMethodDemo[41943:3974856] property === description
2018-03-06 15:07:35.033972+0800 AddMethodDemo[41943:3974856] property === debugDescription
2018-03-06 15:07:35.034094+0800 AddMethodDemo[41943:3974856]
--------------协议列表------------------
2018-03-06 15:07:35.034324+0800 AddMethodDemo[41943:3974856] RuntimeProtocol
2018-03-06 15:07:35.034509+0800 AddMethodDemo[41943:3974856]
-[ViewController printPerson]@"NSString"_age
2018-03-06 15:07:41.156230+0800 AddMethodDemo[41943:3974856] name:sex:
2018-03-06 15:07:41.156435+0800 AddMethodDemo[41943:3974856] personTest 2
2018-03-06 15:07:41.156618+0800 AddMethodDemo[41943:3974856] person T@"Person",&,N,V_person
2018-03-06 15:07:41.156754+0800 AddMethodDemo[41943:3974856] T @"Person"
2018-03-06 15:07:41.156919+0800 AddMethodDemo[41943:3974856] &
2018-03-06 15:07:41.157050+0800 AddMethodDemo[41943:3974856] N
2018-03-06 15:07:41.157174+0800 AddMethodDemo[41943:3974856] V _person
2018-03-06 15:07:41.157331+0800 AddMethodDemo[41943:3974856] -[ViewController printPerson]add Property success
2018-03-06 15:07:41.157466+0800 AddMethodDemo[41943:3974856]
----------- NSInvocation用法 -----------
2018-03-05 16:42:16.078605+0800 AddMethodDemo[33380:3256539] d:3
2018-03-05 16:42:16.078836+0800 AddMethodDemo[33380:3256539] 你好,
2018-03-05 16:42:16.079003+0800 AddMethodDemo[33380:3256539] MyLog:1,2,3
2018-03-05 16:42:16.079313+0800 AddMethodDemo[33380:3256539] 参数类型 @
2018-03-05 16:42:16.079610+0800 AddMethodDemo[33380:3256539] 参数类型 :
2018-03-05 16:42:16.080265+0800 AddMethodDemo[33380:3256539] 参数类型 i
2018-03-05 16:42:16.080461+0800 AddMethodDemo[33380:3256539] 参数类型 i
2018-03-05 16:42:16.080669+0800 AddMethodDemo[33380:3256539] 参数类型 i
2018-03-05 16:42:16.080917+0800 AddMethodDemo[33380:3256539] 返回值的类型 i
2018-03-05 16:42:16.081114+0800 AddMethodDemo[33380:3256539]
----------- 点击时间延迟 -----------
2018-03-05 16:42:16.082430+0800 AddMethodDemo[33380:3256539]
----------- 动态类 -----------
2018-03-05 16:42:16.082643+0800 AddMethodDemo[33380:3256539] addIvar success
2018-03-05 16:42:16.083097+0800 AddMethodDemo[33380:3256539] -- nameValue: 123str
2018-03-05 16:42:16.083366+0800 AddMethodDemo[33380:3256539] instance height = 15
2018-03-05 16:42:16.083882+0800 AddMethodDemo[33380:3256539] occ_viewWillAppear
class_addMethod(Class cls, SEL name, IMP imp,
const char *types)
Class cos:我们需要一个class,比如我的[Person class]。
SEL name:这个很有意思,这个名字自己可以随意想,就是添加的方法在本类里面叫做的名字,但是方法的格式一定要和你需要添加的方法的格式一样,比如有无参数。(有几个小伙伴问我Demo里面的findInSelf这个方法没有找到,请看这里呀。这个就是里面为啥没有findInSelf方法而可以直接调用的原因)
IMP imp:IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP。这里需要的是IMP,所以你不能直接写方法,需要用到一个方法:
OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
这个方法也是runtime的方法,就是获得对应的方法的指针,也就是IMP。
const char *types:
比如:”v@:”意思就是这已是一个void类型的方法,没有参数传入。
再比如 “i@:”就是说这是一个int类型的方法,没有参数传入。
再再比如”i@:@”就是说这是一个int类型的方法,又一个参数传入。
用这个方法添加的方法是无法直接调用的,必须用performSelector:调用。
因为performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。
添加方法是在运行时添加的,编译的时候还没有这个本类方法。
源码Demo
网友评论