ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

iOS Runtime 执行流程

2021-05-15 17:02:53  阅读:173  来源: 互联网

标签:缓存 流程 cache iOS selector anInvocation Runtime 方法 动态


Runtime 介绍

Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解
Objective-C 的 Runtime
机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime
,要先了解它的核心 - 消息传递 (Messaging)。

Runtime objc_msgSend执行流程

  • 在OC中的方法调用,其实都是转换为objc_msgSend函数的调用,给receiver(方法调用者)发送一条消息(selector
    方法名)

  • objc_msgSend的执行流程可以分为3个阶段

    消息发送
    动态方法解析
    消息转发

ps:如果这三个阶段都找不到方法的话就会报经典错误 unrecognized selector sent to instance

消息发送

  1. 通过receiver(消息接收者)的isa 指针 找到receiver的Class
  2. 在Class的cache(方法缓存)的散列表中寻找对应的IMP(方法实现)
  3. 如果在cache(方法缓存)中没有找到对应的IMP,就继续在Class的methodlist(方法列表)中找对应的selector,如果找到,填充到cache(方法缓存)中,并返回selector;
  4. 如果在class中,没有找到这个selector,就继续在它的superClass中的cache(方法缓存)中查找,如果查到缓存到Class中的cache(方法缓存)中
  5. 如果没有查到,就在superClass中的methodlist中查找,并且缓存到Class中的cache(方法缓存)中
  6. 如果还是没有找到IMP(方法实现),判断是否还是有superClass,如果有重复4,5步骤,如果没有则开始进入到动态方法解析阶段

动态方法解析
源码是否曾经有过动态解析 如果没有 则看开发者有没有实现+resolveInstanceMethod:,resolveClassMethod:方法来动态解析方法 如果实现了该方法,标记为已经动态解析。会重新回到消息发送流程中(在Class的cache中查找方法)这一步开始执行。
如果已经动态解析过 则会进入下一步 消息转发阶段。
例子:

ZQPerson * p = [[ZQPerson alloc]init];
        [p test];
打印结果:-[ZQPerson other]

  • person类中没有实现test方法 而是在resolveInstanceMethod中动态指向了other方法的实现
person.h

@interface ZQPerson : NSObject
- (void)test;
@end

person.m

 - (void)other{
    NSLog(@"%s",__func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    Method otherMethod = class_getInstanceMethod(self, @selector(other));
    if (sel == @selector(test)) {
        class_addMethod(self, sel, method_getImplementation(otherMethod), method_getTypeEncoding(otherMethod));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

消息转发
在消息发送过程中和动态方法解析过程中都没有找到具体的实现,这样就会进入消息转发。
消息转发:将消息转发给别人。
将尝试调用(id)forwardingTargetForSelector:(SEL)aSelector方法 返回值部位nil,就会调用obj_msgSend(返回值,SEL),
如果forwardingTargetForSelector返回为nil,则要实现methodSignatureForSelector,forwardInvocation,这两个方法。

 方法签名:返回值类型,参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if (aSelector == @selector(test)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
        return [super methodSignatureForSelector:aSelector];
    }
    //NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
    //    anInvocation.target // 方法调用者
    //    anInvocation.selector 方法名
    //    [anInvocation getArgument:NULL atIndex:0]; 参数
 - (void)forwardInvocation:(NSInvocation *)anInvocation{
       anInvocation.target = [[ZQCat alloc]init];//指定消息转发接收的对象
        [anInvocation invoke];//执行方法
        
        //或者这样写
        [anInvocation invokeWithTarget:[[ZQCat alloc]init]];
    }

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:642363427不管你是小白还是大牛欢迎入驻
,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

标签:缓存,流程,cache,iOS,selector,anInvocation,Runtime,方法,动态
来源: https://blog.51cto.com/u_15010671/2778076

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有