面试题:讲一下OC的消息机制。
OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方法调用者)发送了一条消息(selector方法名)。objc_msgSend底层有3大阶段:
消息发送(当前类、父类中直接找)、动态方法解析、消息转发。
消息发送:
1.判断消息接受者是否为nil,为nil就退出;
2.不为nil就通过isa指针找到接受者的类对象,查找里面缓存的方法是否有该消息,
1)有就调用方法、结束查找。
2)没有就从rw_t方法列表中查找,
1>.有就调用方法、结束查找、并将方法缓存到该接收者的缓存列表中;
2>.没有就通过superClass指针找到父类,再从父类的缓存列表中查找;
a. 找到就调用方法、结束查找并将方法缓存到该接收者的缓存列表中;
b.没有就从该父类的方法列表中查找;
+ 有就调用方法、结束查找并将方法缓存到该接收者的缓存列表中,
+ 没有就继续通过superClass指针继续查找...;
动态方法解析:
最后整个体系都没有就会进入动态方法解析过程,首先判断是否曾经有过动态解析:
没有的话,调用+resolveInstanceMethod或者+resolveClassMethod:方法来动态解析,
并标记为已经动态解析,然后进入消息发送重复上面的过程,最后到曾经有过动态解析直接转入消息转发。
消息转发:
进入消息转发会调用forwardingTargetForSelector:方法。
返回值不为nil,就会调用objc_msgSend(返回值,SEL);
返回值为nil,调用methodSignatureForSelector:方法:
返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;
返回不为nil,调用forwardInvocation方法
面试题:消息转发机制流程?
首先会去实现forwardingTargetForSelector:方法。
1).如果让该方法去执行,即返回值不为nil,就会调用objc_msgSend(返回值,SEL);
2).返回值为nil,调用methodSignatureForSelector:方法。
a.如果该方法返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;
b.返回不为nil,调用forwardInvocation方法,开发者可以在该方法中自定义任何逻辑。
OC中的方法调用,其实都是转换为objc_msgSend函数的调用。
objc_msgSend(对象,@selector(方法))
objc_msgSend如果找不到合适的方法调用,会报错unrecognized selector send to instance
OC的方法调用:消息机制,给方法调用者发送消息。
objc_msgSend的执行流程可以分为3大阶段
消息发送:
给方法调用者发送消息,尝试找到方法。找到不会往下进行,否则进行动态方法解析。

动态方法解析:
在消息发送阶段没有找到对应的方法,会进入动态方法解析,先判断是否曾经有过动态解析,没有的话,调用+resolveInstanceMethod或者resolveClassMethod:方法来动态解析,并标记为已经动态解析,然后进入消息发送;如果曾经有过动态解析,直接转入消息转发。

添加实例方法

添加类方法

消息转发:将消息转发给别人
调用forwardingTargetForSelector:方法。返回值不为nil,就会调用objc_msgSend(返回值,SEL);
返回值为nil,调用methodSignatureForSelector:方法。返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;返回不为nil,调用forwardInvocation方法


能来到forwardInvocation:方法,可以尽情的做你想做的(可以不写,或者打印)。而如上所写相当于把消息转发给MJCat,完全可以在forwardTargetForSelector:方法中实现。

上面是调用实力方法时出现的消息转发过程,调用类方法不存在时新消息转发过程代码如下:
+ (id)forwardingTargetForSelector

@dynamic :提醒编译器不要自动生成setter,getter方法的实现,不要自动生成成员变量。
意味着需要去实现resolveInstanceMethod:方法

@synthesize:提醒编译器生成setter,getter方法,跟@dynamic 相反。(只是后来的Xcode默认就是要生成setter,getter方法,所以也就不需要写了)
网友评论