博客> objc_msgSend方法调用流程
objc_msgSend方法调用流程
2017-12-13 03:36 评论:0 阅读:174 ios_wj@163.com
ios obc_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);

收藏
0
sina weixin mail 回到顶部