美文网首页
runtime(三)

runtime(三)

作者: dandelionYD | 来源:发表于2019-03-29 20:59 被阅读0次

    objc_msgSend执行流程

    本文Demo代码见gitHubDemo

    我们先来看看一个小例子

    myPerson.h
    #import <Foundation/Foundation.h>
    @interface myPerson : NSObject
    +(void)walk;
    -(void)run;
    -(void)sayHello:(NSString*)name;
    -(NSString*)sayGoodBye:(NSString*)name;
    @end
    
    myPerson.m
    #import "myPerson.h"
    
    @implementation myPerson
    +(void)walk{
        NSLog(@"%s",__FUNCTION__);
    }
    -(void)run{
        NSLog(@"%s",__FUNCTION__);
    }
    -(void)sayHello:(NSString*)name{
        NSLog(@"%s--%@",__FUNCTION__,name);
    }
    -(NSString*)sayGoodBye:(NSString*)name{
        return [NSString stringWithFormat:@"%@",name];
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import "myPerson.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            myPerson *person = [[myPerson alloc]init];
            
            //类方法
            [myPerson walk];
            ((void(*)(id,SEL))objc_msgSend)([myPerson class], @selector(walk));
            
            //实例方法
            //没有返回值,没有参数
            [person run];
            ((void(*)(id,SEL))objc_msgSend)(person, @selector(run));
            
            //没有返回值 ,有一个参数
            [person sayHello:@"Jack"];
            ((void(*)(id,SEL,NSString*))objc_msgSend)(person, @selector(sayHello:),@"Lucy");
            
            //有返回值,有一个参数
            [person  sayGoodBye:@"LaLa"];
            NSString *name =  ((NSString*(*)(id,SEL,NSString*))objc_msgSend)(person, @selector(sayGoodBye:),@"Kitty");
            NSLog(@"%@",name);
        }
        return 0;
    }
    打印:
    07.objc_msgSend执行流程[15708:14500527] +[myPerson walk]
    07.objc_msgSend执行流程[15708:14500527] +[myPerson walk]
    07.objc_msgSend执行流程[15708:14500527] -[myPerson run]
    07.objc_msgSend执行流程[15708:14500527] -[myPerson run]
    07.objc_msgSend执行流程[15708:14500527] -[myPerson sayHello:]--Jack
    07.objc_msgSend执行流程[15708:14500527] -[myPerson sayHello:]--Lucy
    07.objc_msgSend执行流程[15708:14500527] Kitty
    
    分析:
    ((void(*)(id,SEL))objc_msgSend)(person, @selector(run));
    其中:person为消息接收者(receiver)、run为消息名称
    
    OC的方法调用:消息机制,给方法调用者发送消息
    

    要想实现看底层的具体分析:可参考深入解构objc_msgSend函数的实现


    objc_msgSend执行流程

    • OC中的方法调用,其实都是转化为objc_msgSend函数调用

    • objc_msgSend的执行流程分为大致3大阶段

      • 消息发送
      • 动态方法解析
      • 消息转发
    • 源码解读(汇编.s文件)

      【注:在c语言里面定义的函数名,在汇编里面会前缀一个_】

    runtime_10.png

    objc_msgSend消息发送

    runtime_11.png

    objc_msgSend动态方法解析

    runtime_12.png

    objc_msgSend消息转发

    runtime_13.png

    下面我们根据流程:看看应用

    1.动态添加方法

    //1
    myPerson1.h
    #import <Foundation/Foundation.h>
    @interface myPerson1 : NSObject
    -(void)test;//也可以不写(这样调用的时候,通过objc_msgSend来调用方法)
    @end
    
    myPerson1.m
    #import "myPerson1.h"
    #import <objc/runtime.h>
    
    struct method_t {
        SEL sel;
        char *types;
        IMP imp;
    };
    
    @implementation myPerson1
    +(BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(test)) {
            // 获取其他方法
            struct method_t *method = (struct method_t *)class_getInstanceMethod(self, @selector(other));
            
            // 动态添加test方法的实现
            class_addMethod(self, sel, method->imp, method->types);
            
            // 返回YES代表有动态添加方法
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    
    - (void)other{
        NSLog(@"%s", __func__);
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    #import <objc/message.h>
    #import "myPerson1.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            myPerson1 *p1 = [[myPerson1 alloc]init];    
            [p1 test]; 
            //打印:09.动态添加方法[16013:14580544] -[myPerson1 other]
            
            ((void(*)(id,SEL))objc_msgSend)(p1, @selector(test));
            //打印:09.动态添加方法[16013:14580544] -[myPerson1 other]
        }
        return 0;
    }
    
    补充:
    BOOL  class_addMethod(Class cls, SEL name, IMP imp, const char *types){
        if (!cls) return NO;
        mutex_locker_t lock(runtimeLock);
        return ! addMethod(cls, name, imp, types ?: "", NO);
    }
    
    
    =======================================================
    //2.
    myPerson2.h
    #import <Foundation/Foundation.h>
    @interface myPerson2 : NSObject
    @end
    
    myPerson2.m
    #import "myPerson2.h"
    #import <objc/runtime.h>
    
    @implementation myPerson2
    - (void)other{
        NSLog(@"%s", __func__);
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(test)) {
            // 获取其他方法
                Method method = class_getInstanceMethod(self, @selector(other));
            
                // 动态添加test方法的实现
                class_addMethod(self, sel,
                                method_getImplementation(method),
                                method_getTypeEncoding(method));
                // 返回YES代表有动态添加方法
                return YES;
            }
        return [super resolveInstanceMethod:sel];
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    #import <objc/message.h>
    #import "myPerson2.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            myPerson2 *p2 = [[myPerson2 alloc]init];
            ((void(*)(id,SEL))objc_msgSend)(p2, @selector(test));
        }
        return 0;
    }
    打印:09.动态添加方法[16108:14597000] -[myPerson2 other]
    
    ======================================================
    //3.添加C的方法
    myPerosn3.h
    #import <Foundation/Foundation.h>
    @interface myPerosn3 : NSObject
    @end
    
    myPerosn3.m
    #import "myPerosn3.h"
    #import <objc/runtime.h>
    
    @implementation myPerosn3
    void c_other(id self, SEL _cmd){
        NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(test)) {
            // 动态添加test方法的实现
            class_addMethod(self, sel, (IMP)c_other, "v16@0:8");
            //v:f返回值是void  2个指针16个字节   第一个指针id 类型@ 从0 开始,  第二个 是SEL为 :  从第8个字节开始
            
            // 返回YES代表有动态添加方法
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    @end
    

    2.消息转发(把消息发给别人)

    myPerson.h
    #import <Foundation/Foundation.h>
    @interface myPerson : NSObject
    - (int)test:(int)age;
    @end
    
    myPerson.m
    #import "myPerson.h"
    #import <objc/runtime.h>
    #import "myAnimal.h"
    
    @implementation myPerson
    //该方法也可以不写
    - (id)forwardingTargetForSelector:(SEL)aSelector{
        NSLog(@"%s",__FUNCTION__);
        if (aSelector == @selector(test:)) {
            return nil; 
            
           // objc_msgSend([[myAnimal alloc] init], aSelector)
           // return [[myAnimal alloc] init]; ////如果 不为nil,则直接不走下面的了,会直接objc_msgSend
           
        }
        return [super forwardingTargetForSelector:aSelector];
    }
    
    -(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
        NSLog(@"%s",__FUNCTION__);
        if (aSelector == @selector(test:)) {
    //        return [NSMethodSignature signatureWithObjCTypes:"i@:I"];
            return [[[myAnimal alloc] init] methodSignatureForSelector:aSelector];
        }
        return [super methodSignatureForSelector:aSelector];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
         NSLog(@"%s",__FUNCTION__);
        // 参数顺序:receiver、selector、other arguments
        //    int age;
        //    [anInvocation getArgument:&age atIndex:2];
        //    NSLog(@"%d", age + 10);
        
        
        // anInvocation.target == [[myAnimal alloc] init]; //方法调用者
        // anInvocation.selector == test; //方法名
        // anInvocation的参数:15
        // [[[myAnimal alloc] init] test:15];
    
        [anInvocation invokeWithTarget:[[myAnimal alloc] init]];
        int ret;
        [anInvocation getReturnValue:&ret];
    
        NSLog(@"----%d", ret);
    }
    @end
    
    
    myAnimal.h
    
    #import <Foundation/Foundation.h>
    @interface myAnimal : NSObject
    @end
    
    myAnimal.m
    #import "myAnimal.h"
    @implementation myAnimal
    - (int)test:(int)age{
        return age * 2;
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import "myPerson.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
           myPerson *p = [[myPerson alloc]init];
           NSLog(@"%d",[p test:10]);
        }
        return 0;
    }
    
    打印:
    10.消息转发[16501:14651870] -[myPerson forwardingTargetForSelector:]
    10.消息转发[16501:14651870] -[myPerson methodSignatureForSelector:]
    10.消息转发[16501:14651870] -[myPerson forwardInvocation:]
    10.消息转发[16501:14651870] ----20
    10.消息转发[16501:14651870] 20
    

    3.类方法的消息转发

    1.
    myPerson1.h
    #import <Foundation/Foundation.h>
    @interface myPerson1 : NSObject
    + (void)test;
    @end
    
    myPerson1.m
    #import "myPerson1.h"
    #import <objc/runtime.h>
    #import "myAnimal.h"
    @implementation myPerson1
    + (id)forwardingTargetForSelector:(SEL)aSelector{
        if (aSelector == @selector(test)) return [myAnimal class];
        return [super forwardingTargetForSelector:aSelector];
    }
    @end
    
    ======================================
    myPerson2.h
    #import <Foundation/Foundation.h>
    @interface myPerson2 : NSObject
    + (void)test;
    @end
    
    myPerson2.m
    #import "myPerson2.h"
    
    @implementation myPerson2
    + (id)forwardingTargetForSelector:(SEL)aSelector{
        if (aSelector == @selector(test)) return  nil; //执行下面的methodSignatureForSelector方法
        return [super forwardingTargetForSelector:aSelector];
    }
    
    + (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        if (aSelector == @selector(test)) return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        return [super methodSignatureForSelector:aSelector];
    }
    
    + (void)forwardInvocation:(NSInvocation *)anInvocation{
        NSLog(@"1123");
    }
    @end
    
    =====================================
    myPerson3.h
    #import <Foundation/Foundation.h>
    @interface myPerson3 : NSObject
    + (void)test;
    @end
    
    myPerson3.m
    #import "myPerson3.h"
    #import <objc/runtime.h>
    #import "myAnimal.h"
    
    @implementation myPerson3
    + (id)forwardingTargetForSelector:(SEL)aSelector{
            if (aSelector == @selector(test)) return [[myAnimal alloc] init];//(此时会调用myAnimal的-test方法)
            //(本质: objc_msgSend([[MJCat alloc] init], @selector(test)))
            return [super forwardingTargetForSelector:aSelector];
    }
    @end
    
    
    myAnimal.h
    #import <Foundation/Foundation.h>
    @interface myAnimal : NSObject
    @end
    
    myAnimal.m
    #import "myAnimal.h"
    @implementation myAnimal
    +(void)test{
        NSLog(@"%s",__FUNCTION__);
    }
    - (void)test{
        NSLog(@"%s",__FUNCTION__);
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import "myPerson1.h"
    #import "myPerson2.h"
    #import "myPerson3.h"
    
    // 元类对象是一种特殊的类对象
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            [myPerson1 test];
            [myPerson2 test];
            [myPerson3 test];
        }
        return 0;
    }
    
    打印:
    11.类方法的消息转发[19716:14685988] +[myAnimal test]
    11.类方法的消息转发[19716:14685988] 1123
    11.类方法的消息转发[19716:14685988] -[myAnimal test]
    

    4.@dynamic

    myPerson.h
    #import <Foundation/Foundation.h>
    @interface myPerson : NSObject
    @property (assign, nonatomic) int age;
    @property (assign, nonatomic) double height;
    @end
    
    myPerson.m
    #import "myPerson.h"
    #import <objc/runtime.h>
    
    /*
    说明:写了属性,编译器会自动生成set、get方法,以及 _ 成员变量(@synthesize age = _age, height = _height;)
    @synthesize age = abc也可以(生成对应的abc成员变量)
     */
    
    @implementation myPerson
    //提醒编译器不要自动生成setter和getter的实现、不要自动生成_成员变量
    @dynamic age;
    void setAge(id self, SEL _cmd, int age){
        NSLog(@"age is %d", age);
    }
    
    int age(id self, SEL _cmd){
        return 120;
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(setAge:)) {
            class_addMethod(self, sel, (IMP)setAge, "v@:I");
            return YES;
        } else if (sel == @selector(age)) {
            class_addMethod(self, sel, (IMP)age, "i@:");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    
    //@synthesize age = _age;
    //- (void)setAge:(int)age{
    //    _age = age;
    //}
    //- (int)age{
    //    return _age;
    //}
    @end
    
    
    【main】
    #import <Foundation/Foundation.h>
    #import "myPerson.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            myPerson *p = [[myPerson alloc]init];
            p.age = 100;
            NSLog(@"age = %d",p.age);
        }
        return 0;
    }
    打印:
    12.dynamic[19912:14736298] age is 100
    12.dynamic[19912:14736298] age = 120
    

    友情链接:

    相关文章

      网友评论

          本文标题:runtime(三)

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