美文网首页
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底层实现原理

    一、Runtime介绍二、Runtime源码初探三、Runtime消息传递四、Runtime消息转发五、Runti...

  • Runtime の滥用典型

    不要滥用Runtime !!!不要滥用Runtime !!!不要滥用Runtime !!! 重要的事说三遍?。 先...

  • iOS知识点(13)Runtime

    让你快速上手Runtime 神经病院Objective-C Runtime出院第三天——如何正确使用Runtime...

  • Runtime(三)

    Objc中发送消息是把接受者和消息用中括号括起来,而直到运行时才把消息与方法实现绑定。 objc_msgSend函...

  • runtime(三)

    objc_msgSend执行流程 本文Demo代码见gitHubDemo 我们先来看看一个小例子 要想实现看底层的...

  • 三、RunTime

    注:本文集为自己准备面试时,系统复习的笔记,如大家有兴趣,欢迎阅读并指正 对象、类对象、元类对象 类对象:存储实例...

  • Runtime(三)方法交换

    Runtime(三)方法交换 在刚开始关注Runtime时, 不知道小伙伴们是否听过一种传说 Runtime是Ob...

  • iOS - Runtime相关

    一.什么是 runtime ? 二.runtime的头文件 三.消息发送步骤 四.常用方法 五.应用

  • iOS 常见知识点(一):Runtime

    iOS 常见知识点(二):RunLoop iOS 常见知识点(三):Lock Runtime Runtime 是一...

  • Runtime深入了解

    前言 一、Runtime版本与平台介绍 二、使用Runtime的场景 三、消息机制(Messaging) 四、动态...

网友评论

      本文标题:runtime(三)

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