objc_msgSend方法调用流程

这个方法做的事情不少,举个栗子:

[self printMessageWithString:@"Hello World!"];

这句语句被编译成这样:

objc_msgSend(self,@selector(printMessageWithString:),@"Hello World!");

这个方法先去查找 self 这个对象或者其父类是否响应
@selector(printMessageWithString:),如果从这个类的方法分发表或
者 cache 里面找到了,就调用它对应的函数指针。如果找不到,那就会执行一些其他的东西。步骤如下:
检测这个 selector 是不是要忽略的。比如 Mac OS X 开发,有了垃圾回收就不理会 retain, release 这些函数了。
检测这个 target 是不是 nil 对象。ObjC 的特性是允许对一个 nil 对象执行任何一个方法不会 Crash,因为会被忽略掉。
如果上面两个都过了,那就开始查找这个类的 IMP,先从 cache 里面找,完了找得到就跳到对应的函数去执行。
如果 cache 找不到就找一下方法分发表。
如果还找不到就要开始消息转发逻辑了。
在编译的时候,你定义的方法比如:

-(int)doComputeWithNum:(int)aNum

会编译成:

int aClass_doComputeWithNum(aClass *self,SEL _cmd,int aNum)

然后由 runtime 去调用指向你的这个方法的函数指针。那么之前我们说你发起消息其实不是对方法的直接调用,其实 Cocoa 还是提供了可以直接调用的方法的:

// 首先定义一个 C 语言的函数指针
int (computeNum *)(id,SEL,int);
// 使用 methodForSelector 方法获取对应与该 selector 的杉树指针,跟 objc_msgSend 方法拿到的是一样的
// **methodForSelector 这个方法是 Cocoa 提供的,不是 ObjC runtime 库提供的**
computeNum = (int (*)(id,SEL,int))[target methodForSelector:@selector(doComputeWithNum:)];
// 现在可以直接调用该函数了,跟调用 C 函数是一样的
computeNum(obj,@selector(doComputeWithNum:),aNum);

参考自:理解 Objective-C Runtime

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,814评论 0 9
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 774评论 0 2
  • Runtime是什么 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我...
    SuAdrenine阅读 903评论 0 3
  • 我是离娜,有一个可爱女儿和一个还算爱我的老公。 喜欢读书却读的不多; 喜欢写作却空有想法; 喜欢旅行却总走不出自己...
    离娜ing阅读 271评论 5 3
  • 前支架(后仰支架)
    随笔s阅读 186评论 0 0