博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Objective-C--Runtime机制
阅读量:4679 次
发布时间:2019-06-09

本文共 7798 字,大约阅读时间需要 25 分钟。

个人理解:

简单来说,Objective-C runtime是一个实现Objective-C语言的C库。对象可以用C语言中的结构体表示,而方法(methods)可以用C函数实现。事实上,他们 差不多也是这么干了,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,Objective-C程序员可以在程序运行时创建,检 查,修改类,对象和它们的方法。例如一个普通类,我们写好之后,Runtime会进行处理。最后变成以下结构:

struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;    #if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;//父类    const char *name                                         OBJC2_UNAVAILABLE;//类名    long version                                             OBJC2_UNAVAILABLE;//设备名    long info                                                OBJC2_UNAVAILABLE;//设备信息    long instance_size                                       OBJC2_UNAVAILABLE;//空间大小    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;//类中参数数组    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//类中函数数组    struct objc_cache *cache                                 OBJC2_UNAVAILABLE; //近期使用过的方法,放入这里。快速查找    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//协议数组    #endif} OBJC2_UNAVAILABLE;

通过一个结构体的方式,来存放类中的信息。

再比如,我们调用的实例方法。从本质上来看是用C语言中的函数来实现的,但是在外面我们还是对实例方法使用结构体进行了封装。结构体如下:

struct objc_method {    SEL method_name                                          OBJC2_UNAVAILABLE;//函数名    char *method_types                                       OBJC2_UNAVAILABLE;//method_types是个char指针,存储着方法的参数类型和返回值类型。    IMP method_imp                                           OBJC2_UNAVAILABLE;//函数指针,指向这个函数的首地址}

在重复一下,Objective-C runtime是一个实现Objective-C语言的C库。


几个知识点的简要概述:

Object & Class & Meta Class

什么是Object?

在oc中有一个id的概念。他的定义为:

typedef struct objc_object *id;struct objc_object {
Class isa;};

Objective-C中的object在最后会被转换成C的结构体,而在这个struct中有一个 isa 指针,指向它的类别 Class。

什么是Class?

typedef struct objc_class *Class;struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;    #if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;    const char *name                                         OBJC2_UNAVAILABLE;    long version                                             OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;    long instance_size                                       OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;    #endif} OBJC2_UNAVAILABLE;

上面是类在runtime中的源代码,从这看,类其实也是一个结构体。这个结构体中的isa指向一个Metaclass。

什么是Metaclass?

仔细一看,发现 Class isa,原来,isa(Metaclass)的源码还是类的源码:

typedef struct objc_class *Class;struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;    #if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;    const char *name                                         OBJC2_UNAVAILABLE;    long version                                             OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;    long instance_size                                       OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;    #endif} OBJC2_UNAVAILABLE;

Object, Class, MetaClass三者之间的关系?

20150715212611218

  • Class存放类信息,方法数组存放实例方法;Meta Class存放类信息,方法数组存放类方法。

  • 每一个object都有一个isa指针,isa指针指向自己的Class 每个Class都有一个isa指针指向一个唯一的Meta Class

  • 每一个Meta Class的isa指针都指向最上层的Meta Class(图中的NSObject的Meta Class) 最上层的Meta
  • Class的isa指针指向自己,形成一个回路 每一个Meta Class的super class指针指向它原本Class的 Super
  • Class的Meta Class。但是最上层的Meta Class的 Super Class指向NSObject Class本身
  • 最上层的NSObject Class的super class指向 nil

objective-C中的消息机制?

什么是SEL?

typedef struct objc_selector *SEL;

SEL是一个指向objc_selector结构体的指针。而 objc_selector 的定义并没有在runtime.h中给出定义。

编译器会根据每个方法的方法名为那个方法生成唯一的SEL。只要方法名相同,那么它的SEL就是一样的。每一个方法都对应着一个SEL。

什么是IMP?

typedef id (*IMP)(id, SEL, …);

IMP本质就是一个函数指针,这个被指向的函数包含一个接收消息的对象id,调用方法的SEL,以及一些方法参数,并返回一个id。因此我们可以通过SEL获得它所对应的IMP,在取得了函数指针之后,也就意味着我们取得了需要执行方法的代码入口,这样我们就可以像普通的C语言函数调用一样使用这个函数指针。

类中的方法存储?

什么是方法?

typedef struct objc_method *Method;struct objc_method {    SEL method_name                                          OBJC2_UNAVAILABLE;    char *method_types                                       OBJC2_UNAVAILABLE;    IMP method_imp                                           OBJC2_UNAVAILABLE;}                                                            OBJC2_UNAVAILABLE;

方法存放位置?

struct objc_class {    Class isa  OBJC_ISA_AVAILABILITY;    #if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;    const char *name                                         OBJC2_UNAVAILABLE;    long version                                             OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;    long instance_size                                       OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;    #endif} OBJC2_UNAVAILABLE;                                                        OBJC2_UNAVAILABLE;

在创建一个类的时候,我们将类中的实例方法存放到objc_class结构体(类的结构体,前面提到)中的objc_method_list **methodLists中。将类中的类方法存放到相应的MetaClass中的类结构中的objc_method_list **methodLists中。我们可以理解为objc_class中 method list保存了一组SEL<->IMP的映射。

调用方法的具体步骤?

在Objective-C中,消息直到运行时才会绑定到方法的实现上。编译器会把代码中[target doSth]转换成 objc_msgSend消息函数,这个函数完成了动态绑定的所有事情。它的运行流程如下:

  • 检查selector是否需要忽略。(ps: Mac开发中开启GC就会忽略retain,release方法。)
  • 检查target是否为nil。如果为nil,直接cleanup,然后return。(这就是我们可以向nil发送消息的原因。)
  • 然后在target的Class中根据Selector去找IMP

寻找IMP的过程:

  • 先从当前class的cache方法列表(cache methodLists)里去找
  • 找到了,跳到对应函数实现
  • 没找到,就从class的方法列表(methodLists)里找
  • 还找不到,就到super class的方法列表里找,直到找到基类(NSObject)为止
  • 最后再找不到,就会进入动态方法解析和消息转发的机制。(这部分知识,)

objective-C中的Category?

看Category的源码,不用想就知道这个又是一个结构体

typedef struct objc_category *Category;struct objc_category {    char *category_name                                      OBJC2_UNAVAILABLE;//分类名    char *class_name                                         OBJC2_UNAVAILABLE;//类名    struct objc_method_list *instance_methods                OBJC2_UNAVAILABLE;//实例方法列表    struct objc_method_list *class_methods                   OBJC2_UNAVAILABLE;//类方法列表    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//协议列表}

运行过程:

  • 加载Category
  • 将Category加载到所属的类中
  • 将Category中的方法加载到Class或者MetaClass结构体中的方法列表中
    (具体看的运行代码)

objective-C中的成员变量与属性?

什么是成员变量?

typedef struct objc_ivar *Ivar;struct objc_ivar {    char *ivar_name                                          OBJC2_UNAVAILABLE;    char *ivar_type                                          OBJC2_UNAVAILABLE;    int ivar_offset                                          OBJC2_UNAVAILABLE;#ifdef __LP64__    int space                                                OBJC2_UNAVAILABLE;#endif}

这里我们注意第三个成员 ivar_offset。它表示基地址偏移字节。我们通过字节偏移量来获取变量的地址。(具体方式不展开)

成员变量存放位置?

存放在之前我们仿佛强调的objc_class中的struct objc_ivar_list *ivars中 。

属性和成员变量的区别?

类中的Property属性被编译器转换成了Ivar,并且自动添加了我们熟悉的Set和Get方法。


讲解Runtime,结合代码和题目

刨根问底Objective-C Runtime(1)- Self & Super
刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
刨根问底Objective-C Runtime(3)- 消息和Category
刨根问底Objective-C Runtime(4)- 成员变量与属性

这一系列文章中,讲的很全面,但是没有结合源代码具体来看

转载于:https://www.cnblogs.com/AbeDay/p/5026897.html

你可能感兴趣的文章
解决【win10管理员已阻止程序运行】问题时有感
查看>>
NumPy切片和索引
查看>>
Linux CentOS7 VMware 文件和目录权限chmod、更改所有者和所属组chown、umask、隐藏权限lsattr/chattr...
查看>>
易语言拖拽文件命令,拖放对象组件应用
查看>>
MySQL同步故障:" Slave_SQL_Running:No" 两种解决办法 (转载)
查看>>
Activiti系列——如何在eclipse中安装 Activiti Designer插件
查看>>
Linux系统下,启动Tomcat有时报Address already in use
查看>>
读苹果开发文档时遇到瓶颈,转而花2天看了Objc基本语法
查看>>
来创个博客分享学习一下
查看>>
URAL 1779 F - The Great Team 构造
查看>>
HDU 5629 Clarke and tree dp+prufer序列
查看>>
Codeforces Round #407 div2 题解【ABCDE】
查看>>
23种设计模式的C++实现
查看>>
【关于HBITMAP, DC, MEM DC, Clipboard】将HBITMAP拷贝到Clipboard(Windows Clipboard & OLE Clipboard)...
查看>>
freemarker自定义标签
查看>>
F5-WAF-12.0
查看>>
霸道总裁之所以迷人,才不是因为霸道!
查看>>
本地通知UILocalNotification
查看>>
STM32单片机是如何启动的?
查看>>
数据结构:链表 >> 链表按结点中第j个数据属性排序(冒泡排序法)
查看>>