objc_msgSend底层探索(上)

我这篇文章呢,主要来分析一下objc_msgSend,关于他的一个执行流程和快速查找的过程,那首先我需要了解一下Runtime是怎么调起底层的呢?也就是Runtime是怎么发起的呢?Runtime的发起方式一共有三种。

第一种就是直接从OC层面,调用相关的方法,第二种就是通过NSObject,调用相关的接口,第三种,就是底层提供的objc这类的下层的api,什么意思呢。

在整个的OC层面我们来看一下,第一点,我们写代码都是在OC的Code这一层,就是下图的第一层,那么很多的相关的Framework、Service,是在第二层,Runtime Api也在这一层,比如说objc_getClass、objc_Method等等一些相关的属性的一些接口,就都在这里,然后第三层是Compiler,编译器。

最下面的,就是Runtime System Library,就是底层的一些相关的库,这些库的上层的还原,就是通过编译器从中间层进行拦截来提供一个支持,比如说,还可以提供NSObject的相关的一些接口、Runtime的相关的一些接口,这就是runtime发起的三种形式。

我们再来落地一下,哪三种形式呢,如下图,比如说OC Code,person调用一个方法sayHello,就是调起了Runtime,调起了方法的底层的一些东西。

然后,比如我调用isKindOfClass的时候,就是调用的NSObject的一些相关的接口,Runtime API有哪些呢?比如说,class_getInstanceSize,这就是底层的API。

然后来看代码实现,如下图,我写了一个LGPerson,然后他有一个sayHello和一个sayWorld方法,但是sayWorld是没有进行实现的,sayHello有实现,我在command+B的时候。

提示了Build Succeeded,也就是编译通过了,但是我运行起来之后就报错了,这就是运行时和编译时的区别。

然后我来看底层api是怎么来实现的,打开终端,cd到当前的main.m文件的目录下,输入clang命令:clang -rewrite-objc main.m -o main.cpp,稍等片刻就得到了一个cpp文件,在文件夹中打开它,然后来到最后找到main函数,如下图。

main函数里面的东西,就等效于我的OC代码,在这个重写的过程中,就有一些编译时的相关处理,比如说,我的sayWorld方法,他并不是仅仅跟看起来一样只有一个sayWorld的方法,他在底层做了一些什么事情呢?

可以很直观的看到,有一个函数叫做objc_msgSend,他有两个参数,第一个是person,第二个是sel_registerName("sayWorld”),这就是Runtime的三种发起方式里面的第三种方式,也就是API。

然后可以看到,我在进行alloc的时候,底层也是一个objc_msgSend函数,他第一个参数是objc_getClass("LGPerson"),而sayWorld是传的一个普通的person对象,也就是说,我进行任何的方法的调用,他在底层的名字都叫做objc_msgSend,直观的翻译过来就是消息的发送。

这个函数有两个参数,就意味着消息发送需要两个非常重要的东西,第一个就是这里的person,或者是LGPerson,也就是消息的接收者,第二个是消息的主体,主体就包含了消息名字和参数。

然后我有一个大胆的构想,我既然能够进行这么一个转换操作的话,是不是意味着这个底层的等价表达式一样可以执行达到同样的效果呢?我来验证一下,直接把调用sayHello方法的底层代码拷贝出来,放到OC代码下面,然后运行。

一模一样的打印了Hello!所以我通过这种objc_msgSend的方式,也是一样能够实现OC的方法调用的。这里Runtime的三种方式就用了两种,还一种方式是什么呢?就是直接把这个sel_registerName("sayHello")

改成@selector(sayHello),这三种方式,同时去发起了Runtime,都具备运行时功能。然后我来加点难度,当前是给person对象发送消息,而person只实现sayHello方法,我再写一个LGTeacher,让LGPerson继承自LGTeacher,然后在LGTeacher中实现这个sayWorld方法。

现在按照正常的理解,我给普通的person对象发送一个sayWorld方法,就会调起父类LGTeacher的sayWorld方法,我来运行一下。

没有报错了,然后我再clang一下看看objc_msgSend是不是还是给person发的消息呢?结果依然是给person发的消息,并不是直接给person的父类。

那问题就来了,objc_msgSend是如何让消息传递到父类的呢?难道我要去看他的底层源码吗?先不管这么多,我先全局搜索一下试试。

搜到了一个比较有意思的东西,在objc_msgSend下面有一个objc_msgSendSuper,那这是什么意思呢?翻译过来是消息发送父类,难道可以直接给父类发消息?

我直接来试一下,如果我要用objc_msgSendSuper来sayWorld的话,怎么做呢,首先要明白他是什么样的结构,我把他写在OC代码里面,然后点击跳转到定义。

第一个参数是void*类型的一个结构体,另一个就是SEL,还有其他的一些参数,那第一个参数里面的objc_super又是什么呢?我也不知道,来全局搜索一下看能不能找到。果然就找到了一个。

他也很简单,只有三个参数,第二个参数有一个条件,如果满足__OBJC2__的话,那第二个参数就没有了,也就是说,这个结构体里面只有两个参数了,一个是receiver,一个是super_class,然后我来手动写一个这样的结构,来作为objc_msgSendSuper的第一个参数。

receiver就是接收者,给person对象,super_class按理说我直接给父类LGTeacher.class就可以了,然后把zs_objc_super作为第一个参数给objc_msgSendSuper,指针地址就是&zs_objc_super,剩下的是一个SEL,我就直接给一个@selector(sayWorld)。

报了个错,根据之前调用objc_msgSend的经验,也一样的需要强转一下。

直接运行,完美的执行了sayWorld,并且super_class也可以给LGPerson.class,也是一样的,无非就是多找一层和少找一层的区别。

未完待续...

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

推荐阅读更多精彩内容