Runtime消息发送和消息转发

runtime源码下载

一、理解类对象

类对象
struct objc_class {
    Class _Nonnull isa  // 指向元类;

#if !__OBJC2__
    Class _Nullable super_class                             // 指向父类;
    const char * _Nonnull name                             // 类名;
    long version                                             // 类的版本信息;
    long info                                               
    long instance_size                                       // 类的实例变量大小;
    struct objc_ivar_list * _Nullable ivars                  // 成员变量列表;
    struct objc_method_list * _Nullable * _Nullable methodList  // 对象方法列表;
    struct objc_cache * _Nonnull cache                       // 最近使用的方法缓存,优先在这里查找方法;
    struct objc_protocol_list * _Nullable protocols          // 协议列表;
#endif

} OBJC2_UNAVAILABLE;

1,objc对象isa 指针指向他的类对象。
2,类对象中也有一个isa指针指向它的元类(meta class),即类对象是元类的实例。
3,元类内部存放的是类方法列表,isa指针指向根元类,根元类的isa指针指向自己,superclass指针指向NSObject类。
4,根对象就是NSObject,它的superclass指针指向nil。

二、消息发送

向对象传递消息,会使用动态绑定机制来决定决定需要调用的方法,在底层,所有方法都是C语言函数,对象收到消息后,究竟调用那个方法取决于运行期,所以Objective-C是一门真正的动态语言。

给对象发送消息,编辑器会将其转换为一条C语言函数调用,objc_msgSend,原型:

void objc msgSend (id self, SEL cmd, ...)

第一个参数代表接收者,第二个参数代表选择子(SEL 是选择子的类型),后续参数就是消息中的那些参数,其顺序不变。

objc_msgSend 函数会依据接收者与选择子的类型来调用适当的方法。在接收者所属的类中搜寻其“方法列表”(list of methods),如果能找到与选择子名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找到合适的方法之后再跳转。如果最终还是找不到相符的方法,那就执行“消息转发” (messags forwarding)操作。
这么说来,想调用一个方法似乎需要很多步骤。所幸 objc_ msgSend 会将匹配结果缓在“快速映射表”(ftast map)里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择子相同的消息,那么执行起来就很快了。

这只是部分消息的调用过程,其他“边界情况”(edge case)则需要交由 Objective-C 运行环境中的另一些函数来处理:

  • objc_msgSend_stret。如果待发送的消息要返回结构体,那么可交由此函数处理。只有当CPU 的寄存器能够容纳得下消息返回类型时,这个函数才能处理此消息。若是返回值无法容纳于 CPU 寄存器中(比如说返回的结构体太大了),那么就由另一个函数执行派发。此时,那个函数会通过分配在栈上的某个变量来处理消息所返回的结构体。
  • objc_msgSend_fpret。 如果消息返回的是浮点数,那么可交由此函数处理。在某些架构的 CPU 中调用函数时,需要对 “浮点数寄存器(foating-point register)做特殊处理,也就是说,通常所用的 objc_msgSend 在这种情况下并不合适。这个函数是为了处理
    ×86 等架构 CPU 中某些令人稍觉惊讶的奇怪状况。
  • objc_ msgSendSuper。如果要给超类发消息,例如 [super message:parameter],那么就交由此函数处理。也有另外两个与 objc_msgSend_ stret 和 objc_msgSend fpret 等效的函数,用于处理发给 super 的相应消息。

刚才提到,objc_msgSend 等函数一旦找到应该调用的方法文现”之后,就会“跳转过去”。之所以能这样做,是因为 Objiective-C 对象的每个方法都可以视为简单的C 函数,其原型如下:
<return type> Class selector (id self, SEI _end, ...)
真正的函数名和上面写的可能不太一样,用 “类”(class)和“选择子”(selector)来命名是想解释其工作原理。每个类里都有一张表格,其中的指针都会指向这种C语言函数,而选择子的名称则是查表时所用的“键”。objc_msgSend 等函数正是通过这张表格来寻找应该执行的方法并跳至其实现的。请注意,原型的样子和 objc_msgSend函数很像。这不是巧合,而是为了利用 “尾调用优化”(tail-call optimization)技术,令“跳至方法实现” 这一操作变得更简单些。

如果某两数的最后一项操作是调用另外一个函数,那么就可以运用 “尾调用优化”技术。编译器会生成调转至另一两数所需的指令码,而且不会向调用堆栈中推人新的“栈帧” (frame stack)。只有当某两数的最后一个操作仅仅是调用其他两数而不会将其返回值另作他用时,才能执行一尾调用优化”。这项优化对 obje msgSend 非常关键,如果不这么做的话,那么每次调用 Objective-C 方法之前,都需要为调用 objc_ msgSend 函数准备“栈帧”,大家在“栈踪迹”(stack trace)中可以看到这种“栈帧”。此外,若是不优化,还会过早地发生“栈溢出”(stack overflow)现象。

三、消息转发

书籍:Effective Objective-C 2.0

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

推荐阅读更多精彩内容