美文网首页
iOS【运行时态基本用法】

iOS【运行时态基本用法】

作者: NJ_墨 | 来源:发表于2018-03-01 15:02 被阅读19次

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

相关文章

网友评论

      本文标题:iOS【运行时态基本用法】

      本文链接:https://www.haomeiwen.com/subject/bnmgxftx.html