Runtime运行时机制简单总结

来源:互联网 发布:手机淘宝怎么抢红包 编辑:程序博客网 时间:2024/05/21 02:49

/* 
什么是runtime(运行时机制): 
*/ 
Objective-C是基于C语言加入了面向对象特性和消息转发机制的动态语言,这意味着它不仅需要一个编译器,还需要Runtime系统来动态创建类和对象,进行消息发送和转发。Objc 从三种不同的层级上与 Runtime 系统进行交互,分别是通过 Objective-C 源代码,通过 Foundation 框架的NSObject类定义的方法,通过对 runtime 函数的直接调用。

1.runtime是一套比较底层的纯C语言API, 属于1C语言库, 包含了很多底层的C语言API。2.平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

/* 
runtime的作用: 
*/

runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法实现的)。

1.在程序运行过程中, 动态创建一个类(比如KVO的底层实现)2.在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法3.遍历一个类的所有成员变量(属性)\所有方法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

/* 
runtime相关应用: 
*/

* NSCoding(归档和解档, 利用runtime遍历模型对象的所有属性)* 字典 --> 模型 (利用runtime遍历模型对象的所有属性, 根据属性名从字典中取出对应的值, 设置到模型的属性上)* KVO(利用runtime动态产生一个类)* 用于封装框架(想怎么改就怎么改)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

/* 
Runtime数据结构: 
*/

在Objective-C中,使用[receiver message]语法并不会马上执行receiver对象的message方法的代码,而是向receiver发送一条message消息,这条消息可能由receiver来处理,也可能由转发给其他对象来处理,也有可能假装没有接收到这条消息而没有处理。其实[receiver message]被编译器转化为:

id objc_msgSend ( id self, SEL op, ... );
  • 1
  • 1

下面简单介绍runtime中重要的数据结构:

SEL 
表示方法选择器。其实它就是映射到方法的C字符串,你可以通过Objc编译器命令@selector()或者Runtime系统的sel_registerName函数来获取一个SEL类型的方法选择器。

id 
id是通用类型指针,能够表示任何对象。id其实就是一个指向objc_object结构体指针,它包含一个Class isa成员,根据isa指针就可以顺藤摸瓜找到对象所属的类。

Class 
Class表示对象所属的类。可以查看到Class其实就是一个objc_class结构体指针。在面向对象设计中,一切都是对象,Class在设计中本身也是一个对象。

Method 
Method表示类中的某个方法。其实Method就是一个指向objc_method结构体指针,它存储了方法名(method_name)、方法类型(method_types)和方法实现(method_imp)等信息。

Ivar 
Ivar表示类中的实例变量。Ivar其实就是一个指向objc_ivar结构体指针,它包含了变量名(ivar_name)、变量类型(ivar_type)等信息。

IMP 
IMP本质上就是一个函数指针,指向方法的实现。当你向某个对象发送一条信息,可以由这个函数指针来指定方法的实现,它最终就会执行那段代码,这样可以绕开消息传递阶段而去执行另一个方法实现。

Cache 
Cache主要用来缓存。Cache其实就是一个存储Method的链表,主要是为了优化方法调用的性能。当调用方法时,优先在Cache查找,如果没有找到,再到methodLists查找。

/* 
Runtime消息发送: 
*/

前面从objc_msgSend作为入口,逐步深入分析Runtime的数据结构,了解每个数据结构的作用和它们之间关系后,我们正式转入消息发送这个正题。

objc_msgSend函数

  在前面已经提过,当某个对象使用语法[receiver message]来调用某个方法时,其实[receiver message]被编译器转化为:

id objc_msgSend ( id self, SEL op, ... );
  • 1
  • 1

现在让我们看一下objc_msgSend它具体是如何发送消息:

1.首先根据receiver对象的isa指针获取它对应的class2.优先在class的cache查找message方法,如果找不到,再到methodLists查找3.如果没有在methodLists找到,再到super_class查找4.一旦找到message这个方法,就执行它实现的IMP。

/* 
方法解析与消息转发: 
*/

[receiver message]调用方法时,如果在message方法在receiver对象的类继承体系中没有找到方法,那怎么办?一般情况下,程序在运行时就会Crash掉,抛出 unrecognized selector sent to …类似这样的异常信息。但在抛出异常之前,还有三次机会按以下顺序让你拯救程序。

1.Method Resolution2.Fast Forwarding3.Normal Forwarding

/* 
三种方法的选择: 
*/

Runtime提供三种方式来将原来的方法实现代替掉,那该怎样选择它们呢?

1.Method Resolution:由于Method Resolution不能像消息转发那样可以交给其他对象来处理,所以只适用于在原来的类中代替掉。2.Fast Forwarding:它可以将消息处理转发给其他对象,使用范围更广,不只是限于原来的对象。3.Normal Forwarding:它跟Fast Forwarding一样可以消息转发,但它能通过NSInvocation对象获取更多消息发送的信息,例如:target、selector、arguments和返回值等信息。

/* 
method Swizzling: 
*/

就是在运行时将一个方法的实现代替为另一个方法的实现。如果能够利用好这个技巧,可以写出简洁、有效且维护性更好的代码。

总结:

虽然在平时项目不是经常用到Objective-C的Runtime特性,但当你阅读一些iOS开源项目时,你就会发现很多时候都会用到。所以深入理解Objective-C的Runtime数据结构、消息转发机制有助于你更容易地阅读和学习开源项目。

想要了解更多有关Runtime 请戳《Objective-C特性:Runtime》

0 0
原创粉丝点击