美文网首页
Runtime-原理

Runtime-原理

作者: 亲爱的大倩倩 | 来源:发表于2019-07-03 18:16 被阅读0次

runtime初探
对象与方法的本质
runtime-消息发送
runtime-动态方法解析
runtime-消息转发

runtime
runtime是由C,C++,汇编一起写成的一套api
而OC提供了运行时

运行时和编译时
编译时:为你正在编译的时间,把源代码翻译成可以识别的语言,OC,Swift,JAVA都是高级语言,不能被机器识别,所以需要编译成相应的机器语言二进制,
因为二进制比较难写代码,所以才延伸出高级语言让我们编译

运行时:当代码跑起来后,会被装载到内存,当编译一个项目后,product里面会有一个app,打开包内容里面会看到被编译到沙盒里的可执行文件

当代码装载到内存后,就活了

下面看运行时功能

C和C++汇编提供给运行时带来的OC功能

OC提供运行时,当一个方法没有实现时,在编写代码时,C语言就会报错,但是OC不会,只会在运行时报错

OC对象的本质是一个结构体
方法的本质是发送消息objc_msgSend(参数1为消息接收者,参数2为消息编号),通过SEL去找到IMP
消息的组成:
(id)p消息接收者
sel_registerName("run")方法编号

任何一个方法调用,在底层都是一个类似于如此的

SEL _cmd为方法编号
IMP为函数实现的指针
void runIMP(id self,SEL _cmd){ 
}

当调用某个方法时,其实底层是

LGPerson *p = [[LGPerson alloc] init];
[p run];
//原理
LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));

#解说
任何方法的调用都会被编译成objc_msgSend方法
第一句代码是将objc_msgSend方法强转成((LGPerson *(*)(id, SEL))类型,参数一id为对象(id)objc_getClass("LGPerson"),参数二SEL为消息是sel_registerName("new")

runtime的三种调用方式
1.runtime的api
2.NSObject会提供的api
3.编译器提供的OC上层方法,类似于@selector

sel_registerName("run")等于@selector(run)

对象方法编译底层

LGStudent *s = [LGStudent new];
[s run];
objc_msgSend(s, sel_registerName("run"));

类方法编译底层

id cls = [LGStudent class];
void *pointA = &cls;
[(__bridge id)pointA walk];
objc_msgSend(objc_getClass("LGStudent"), sel_registerName("walk"));

向父类发消息(对象方法)

struct objc_super mySuper;
mySuper.receiver = s;
mySuper.super_class = class_getSuperclass([s class]);
objc_msgSendSuper(&mySuper, @selector(run));

向父类发消息(类方法)

struct objc_super myClassSuper;
myClassSuper.receiver = [s class];
myClassSuper.super_class = class_getSuperclass(object_getClass([s class]));// 元类
objc_msgSendSuper(&myClassSuper, sel_registerName("walk"));

对象方法存在类中,是一个实例方法
类方法存在元类中,也是一个实例方法

objc_msgSend 是汇编写成的
有两种方式
1.快速:在缓存中直接通过汇编
2.慢速:C配合C++以及汇编一起完成的

缓存来源于类
看下类结构,bits是所有的数据,每个类里面都有cache,用来存储方法和IMP,IMP和@selector会组成一张哈希表

当我们调用一个方法时
1.先找cache
2.通过SEL去哈希表中找IMP
3.若是没找到,就会用慢速(C配合C++以及汇编一起完成)去找,找到后会去缓存中存一份,方便下次查找

为什么是汇编写的

  1. C语言不可能通过写一个函数来直接保留未知的参数,然后跳转到任意的指针,而objc_msgSend是运行时,通过传进来的对象和@selector去查找的,C无法实现
    2.汇编很快,汇编有寄存器,在底层可以直接编译

消息发送objc_msgSend源码分析流程


动态方法解析_源码分析流程
当消息调用时,如果

消息转发 作用
可以在forwardingTargetForSelector中进行
1.自定义处理
2.收集crash
3.防止崩溃
可以在forwardInvocation中
1.系统调用堆栈,存到沙盒里发给服务器,类似友盟收集崩溃
2.切面编程,埋点统计

runtime应用

self不一定是当前类,谁调用是谁

相关文章

  • Runtime-原理

    runtime初探对象与方法的本质runtime-消息发送runtime-动态方法解析runtime-消息转发 r...

  • runtime-整理中

    runtime-整理中

  • Runtime-原理与应用

    使用运行时前提,必须导入#import 1.runtime使用技巧 谁来发生动作...

  • 底层技术以及runtime分享

    https://minilv.github.io/2019/03/17/Runtime-消息机制土味讲解/?nsu...

  • Runtime- objc_msgSend执行流程

    Runtime- objc_msgSend执行流程 1.消息发送 receiver是否为nil,如果是nil直...

  • Swift Runtime-引用计数

    前言 在Swift Runtime-初探一文里,我们初步研究了对象的内存结构.有metadata及Refcount...

  • Runtime-类

    这里会把类相关、程序启动类信息填充、引用计数都会讲下。想要深入了解OC的动态性,就必须去研究runtime的代码,...

  • Runtime-开篇

    关于Class和Id 当你写一个Class去看系统的API时:typedef struct objc_class ...

  • Runtime-应用

  • Runtime-方法

    01class的结构 元类对象和元类的结构是一样的,他是一种特殊的类对象 class_rw_t里面的methods...

网友评论

      本文标题:Runtime-原理

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