美文网首页
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