Runtime(三)

2016-12-12  本文已影响24人  CRAZYBADAM

Objc中发送消息是把接受者和消息用中括号括起来,而直到运行时才把消息与方法实现绑定。

objc_msgSend函数

objc_msgSend不返回数据而是你的方法被调用返回了数据,消息发送步骤:

1.检测selector是否要忽略。

2。检测target是否为nil。nil的话会被忽略掉。

3 查找类的IMP指针,先从cache找,找到就去对应函数执行。

4 如果cache找不到就去方法分发表找。

5,如果找不到,就去超类的方法分发表找。一直找到NSObject类为止。

6 如果还找不到,就开始进入动态方法解析。

编译器会根据情况在objc_msgSend,objc_msgSend_stret,objc_msgSendSuper, 或objc_msgSendSuper_stret四个方法中选择一个来调用。

方法中的隐藏参数

经常用self调用实例,为什么就能调用到方法对象呢。

当objc_msgSend找到方法对应的实现时,它将直接调用该方法实现,并将消息中所有的参数都传递给方法实现,同时,它还将传递两个隐藏的参数:

接收消息的对象(也就是self指向的内容)

方法选择器(_cmd指向的内容)

之所以说它们是隐藏的是因为在源代码方法的定义中并没有声明这两个参数。它们是在代码被编译时被插入实现中的。尽管这些参数没有被明确声明,在源代码中我们仍然可以引用它们。在下面的例子中,self引用了接收者对象,而_cmd引用了方法本身的选择器:

- strange

{

id  target = getTheReceiver();

SEL method= getTheMethod();

if( target ==self||method== _cmd )

return nil;

return [target performSelector:method];

}

self 是在方法实现中访问消息接收者对象的实例变量的途径。

而当方法中的super关键字接收到消息时,编译器会创建一个objc_super结构体:

struct objc_super{id receiver; Class class;};

这个结构体指明了消息应该被传递给特定超类的定义。但receiver仍然是self本身,这点需要注意,因为当我们想通过[super class]获取超类时,编译器只是将指向self的id指针和class的SEL传递给了objc_msgSendSuper函数,因为只有在NSObject类才能找到class方法,然后class方法调用object_getClass(),接着调用objc_msgSend(objc_super->receiver, @selector(class)),传入的第一个参数是指向self的id指针,与调用[self class]相同,所以我们得到的永远都是self的类型。

上一篇下一篇

猜你喜欢

热点阅读