Runtime

Runtime是什么

将一些在编译、链接过程中的工作,放到运行阶段,因此Objective-C为动态语言

Runtime是一个库,这个库使我们可以在程序运行时创建对象、检查对象、修改类和对象的方法。

Runtime是怎么工作的

Class和Object

objc.h中,Class被定义为指向objc_class的指针,定义如下:

typedef struct objc_class *Class;

objc_class是一个结构体,在runtime.h中的定义如下:

struct objc_class {
    // isa指针指向的类结构称为metaclass,其中存放着static类型的成员变量与static类型的方法(“+”开头的方法)
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    // 指向该类的父类的指针,如果该类是根类(如NSObject或NSProxy),那么super_class就为nil。
    Class super_class                                        OBJC2_UNAVAILABLE; // 父类
    const char *name                                         OBJC2_UNAVAILABLE; // 类名
    long version                                             OBJC2_UNAVAILABLE; // 类的版本信息,可以通过runtime函数class_setVersion或者class_getVersion进行修改、读取
    long info                                                OBJC2_UNAVAILABLE; // 类信息,供运行时期使用的一些位标识、如CLS_CLASS(0x1L)表示该类为普通 class,其中包含实例方法和变量;CLS_META(0x2L)表示该类为metaclass,其中包含类方法;
    long instance_size                                       OBJC2_UNAVAILABLE; // 该类的实例变量大小(包括从父类继承下来的实例变量)
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE; // 该类的成员变量地址列表
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE; // 方法的地址列表,与info的一些标识位有关,如CLS_CLASS(0x1L)则存储实例方法,如CLS_META(0x2L),则存储类方法;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE; // 缓存最近使用的方法列表,用于提升效率
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE; // 存储该类声明遵守的协议
#endif

} OBJC2_UNAVAILABLE;

一个类包含了自身所有的成员变量(ivars)、所有的方法(methodLists)、实现的协议(protocols

isa的定义如下:

struct objc_object {
    // 是一个指向objc_class结构体的指针
    // objc_object(实例对象)中isa指针指向的类结构称为class(也就是该对象所属的类)其中存放着普通成员变量与动态方法(“-”开头的方法)
    Class isa  OBJC_ISA_AVAILABILITY;
};

一个对象唯一保存的信息就是它的Class的地址

调用对象方法的实现过程

  1. 通过isa去找到对应的objc_class;
  2. objc_classmethodLists中找到我们调用的方法,然后执行。

Meta Class 元类

Objective-C中,类也被设计为一个对象。

调用对象类方法的实现过程(不考虑继承)

  1. 通过对象的isa指针找到对应的类;
  2. 通过类的isa指针找到对应元类;
  3. 在元类的methodList中,找到对应的方法,然后执行。
所有的metaclass中isa指针都是指向根metaclass,而根metaclass则指向自身。根metaclass是通过继承根类产生的,与根class结构体成员一致,不同的是根metaclass的isa指针指向自身。

Method

定义如下:

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE; // 方法名
    char *method_types                                       OBJC2_UNAVAILABLE; // 方法类型
    IMP method_imp                                           OBJC2_UNAVAILABLE; // 方法实现
}

SEL是一个指向objc_selector的指针,而非objc_selector在头文件中找不到明确的定义。不过是一个保存方法名的字符串。

IMP函数指针:找到函数地址,然后执行函数。

typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...)

id对于实例方法来说,self保存了当前对象的地址;对于类方法来说,self保存了当前对应类对象的地址;后面的省略号即是参数列表。

Method建立了SELIMP的关联,当对一个对象发送消息时,会通过给出的SEL去找到IMP,然后执行。

objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)

当向一个对象发送消息时,会去这个类methodLists中查找对应的SEL,如果查不到,则通过super_class指针找到父类,再去父类的methodLists中查找,层层递进。最后仍然找不到,才走抛异常流程。

拦截调用和消息转发流程
重写

resolveClassMethod:
resolveInstanceMethod:

消息发送

基本的消息发送框架

objc_msgSend函数的调用过程:

  • 第一步:检测这个selector是不是要忽略的。
  • 第二步:检测这个target是不是nil对象。nil对象发送任何一个消息都会被忽略掉。
  • 第三步:
    1.调用实例方法时,它会首先在自身isa指针指向的类(classmethodLists中查找该方法,如果找不到则会通过classsuper_class指针找到父类的类对象结构体,然后从methodLists中查找该方法,如果仍然找不到,则继续通过super_class向上一级父类结构体中查找,直至根class
    2.当我们调用某个某个类方法时,它会首先通过自己的isa指针找到metaclass,并从其中methodLists中查找该类方法,如果找不到则会通过metaclasssuper_class指针找到父类的metaclass对象结构体,然后从methodLists中查找该方法,如果仍然找不到,则继续通过super_class向上一级父类结构体中查找,直至根metaclass
  • 第四部:前三部都找不到就会进入动态方法解析(看下文)。
动态方法解析
  • 第一步:通过resolveInstanceMethod:方法决定是否动态添加方法。如果返回Yes则通过class_addMethod动态添加方法,消息得到处理,结束;如果返回NO,则进入下一步;

  • 第二步:这步会进入forwardingTargetForSelector:方法,用于指定备选对象响应这个selector,不能指定为self。如果返回某个对象则会调用对象的方法,结束。如果返回nil,则进入第三部;

  • 第三部:这步我们要通过methodSignatureForSelector:方法签名,如果返回nil,则消息无法处理。如果返回methodSignature`,则进入下一步;

  • 第四部:这步调用forwardInvocation:方法,我们可以通过 anInvocation对象做很多处理,比如修改实现方法,修改响应对象等,如果方法调用成功,则结束。如果失败,则进入doesNotRecognizeSelector方法,若我们没有实现这个方法,那么就会crash

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; // 协议列表
}       

objc_category中包含对象方法列表、类方法列表、协议列表。

可以通过关联对象的方式给类别添加可用的属性

Runtime的常规操作

  1. Method Swizzling方法交换
  2. 获取所有属性和方法

Runtime的应用场景

  1. AOP面向切面编程(对业务逻辑进行分离,降低耦合度)
  2. 字典转模型
  3. 进行归解档
  4. 逆向开发
  5. 热修复

新手也看得懂的 iOS Runtime 教程
RSSwizzle源码解析
Objective-C Runtime 1小时入门教程
深入理解Objective-C:Category

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,715评论 0 9
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,195评论 0 7
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 733评论 0 2
  • Objective-C语言是一门动态语言,他将很多静态语言在编译和链接时期做的事情放到了运行时来处理。这种动态语言...
    tigger丨阅读 1,402评论 0 8
  • 2018年3月31号,晋城市心理学会第二小组第二次成长团体课如期举行。本次主持人是张海燕老师。活动中,张老...
    rainbow琴阅读 91评论 0 0