为什么设计元类
如果从runtime的objc_msgSend角度出发,此种设计主要是为了复用消息机制,并提高消息发送效率。
oc在调用过程中,编译后实际上是使用了objc_msgSend进行消息发送。我们知道,实例方法(比如-(void)A号方法)属性等,存储位置在类中。同时我们每一次初始化alloc一个实例对象后,此实例对象也都会默认保存一个isa指针,指向类。我们在编写代码写的调用方法,在编译完成后都会使用runtime编译称此种形式
id objc_msgSend(id self, SEL op, ...)
这个函数有俩个隐式的参数:消息的接收者,消息的⽅法名。通过这俩个参数就能去找到对应⽅法的实现。所以如果正常情况下,编译期间只接调用就可以,因为isa指针和参数名称在【A对象 A】这种中括号发送小时时候都能拿到。这样看的话,对于实例对象来说并没有什么影响。
但是,问题来了,oc中类方法+号方法和实例方法-号方法是可以同名的。比如项目中可以同时存在+A方法和-A方法。如果此种方式的话,编译后的objc_msgSend要怎么处理????解决方法就是增加的新参数,标记是类方法还是实例方法。还需要一个参数标记接受消息的对象是实例对象还是类对象。
显然是不可能的,objc_msgSend方法作为oc这门语言的设计基础,消息发送效率肯定是越快越好。如果没有元类主动区分开,在运行时,在objc_msgSend这个重度使用方法逻辑中去做大量的其他区分,无疑是对运行效率的大量浪费。
所以元类的出现就解决了这个问题,让各类各司其职,实例对象就⼲存储属性值的事,类对象存储实例⽅法列表,元类对象存储类⽅法列表,符合设计原则中的单⼀职责,⽽且忽略了对对象类型的判断和⽅法类型的判断可以⼤⼤的提升消息发送的效率,并且在不同种类的⽅法⾛的都是同⼀套流程,在之后的维护上也⼤⼤节约了成本。
此外在objc底层没有类⽅法和实例⽅法的区别,都是函数。
我们可以通过runtime中提供的函数证明这一点

然后我们看下源码中class_getInstanceMethod的方法实现

从此处我们也可以看到,类方法在元类中的存储方式和实例方法在类中的存储方法,并无二致。针对于runtime获取方式来说,类方法和实例方法其实都是函数,只是保存的位置有所区别。