类方法转发
本文大约750字,将会介绍对类方法的消息转发,它能帮助我们解决类方法的unrecognized selector crash,或是应对一些其它需要转发的场景
!!!原创文章,转载请注明来源: pany.fun
如果你对消息转发流程还不熟悉,请先行了解 Objective-C 中的消息与消息转发
熟悉以后我们知道,其实消息的转发可以非常简单,简单到可能几行代码就能搞定
- (id)forwardingTargetForSelector:(SEL)aSelector {
// TODO: forward
return target;
}
这就是一个最简单的消息转发方案
# 问题
我司最近有一个需求需要用到消息转发,于是我们也是啪啪啪就敲上了上面的几行代码,分分钟搞定需求,一切都很顺利。
但是我们在测试类方法的时候,问题出现了—— forward方法居然没有执行🤔
按到理解,NSObject是root类,那么所有找不到的方法应该都能走到NSObject
于是我们把上面的forward方法写在了NSObject的分类里进行测试 (正常开发不建议在分类中重写如此敏感的方法)
分类中的方法会覆盖原类中的方法,也就是说,我们在分类中写的forward方法能够拿到所有的forward消息
然后我们再次测试类方法,发现即使是分类里的forward方法,也没有被执行,但是测试实例方法确实是能够执行到的
查询NSObject.h也没有发现任何能够简单转发类方法的接口
# 真相
真相当然只有一个,我们怀疑forward没生效是因为消息链路中有可疑人物已经处理了forward,最可疑的当然是NSObject
考虑到我们测试实例方法可行而类方法不可行,我们将目标进一步定位在了NSObject的meta类上
所以我们自然而然的想要给NSObject的原来添加forward方法,于是我们在NSObject的分类中硬塞了一个这样的方法
+ (id)forwardingTargetForSelector:(SEL)aSelector {
// TODO: forward
return target;
}
需要注意,虽然它跟前面的forward方法名字完全相同,但是它是类方法,所以它会被添加到NSObject的meta类的方法列表中
再次测试类方法,生效!
真相只有一个:NSObject的meta类中包含方法forwardingTargetForSelector,即NSObject还有一个类方法版本的forward,但是它并没有开放在.h中
# 源码
apple没有开放不用怕,毕竟runtime是开源的,我们查询了NSObject的源码
// Line: 2102
+ (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}
- (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}
真相大白
创作不易,转载请注明来源!pany.fun
本文链接:http://pany.fun/post/类方法转发/