从源码理解runtime之super、superclass知识点

801 阅读4分钟

跟大家分享一道关于super和superclass的面试题,也是比较常见的面试题,请看下面的代码:

请问当前的4个结果输出是多少?我们平时写代码估计也不会这么写,面试官问你这些问题,主要是看你对super和superclass是否理解透彻,接下来我们就去分析一下.

首先我们肯定是知道[self class]这个肯定就是当前类,也就是GDStudent;而[self superclass]肯定是它的父类GDPerson

这两个应该是毫无疑问,我们看一下是不是这样,请看下图代码:

这两个是非常明显的答案,我们就来看一下super是怎么回事,这样,我们先来随便在GDStudent写一个方法比如 -(void)test;

.m文件加上实现 如下图:

是不是我们只要搞清楚test里面是怎么调用的,我们就知道super到底做了什么事!所以老样子,我们把GDStudent.m转成底层的c++文件看一下具体的实现是什么样的.只要搞清楚了[super test]做了什么事,其他的问题就迎刃而解了(转成c++的代码我前面说了很多次: xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc GDStudent.m -o GDStudent.m-arm64.cpp)

所以我们只要关注绿色框框的代码就行了,我们把上面的代码简化一下,这样看得更清楚.

上面的就是源码的简化版本,是一摸一样的效果,这里的[super test]就是arg给@selector(test)发一个class_getSuperclass消息,接下来,我们就看一下这个_objc_super的源码里面是怎么实现的(注意这里是去找objc的苹果开源源码,不是刚刚转换的c++的源码,下载地址之前分享了好多次,我现在下载的是787版本),看看结构体里面到底做了什么事!如下图

__rw_objc_super源码实现

__rw_objc_super我们再可以简化一下我们离答案越来越近了,请看简化后的如下图:

这里应该也是非常的清晰吧 self:就是上面的receiver;class_getSuperclass(objc_getClass("GDStudent") :就是上面的 super_class.

接下来我们看最后一个objc_msgSendSuper这个的源码实现,就能解决这个问题了,请看下面的源码:

这里面解释的非常清楚:2个参数,第一个参数就是消息接收者,receiver也就是self,前面的结构体定义很清楚知道;第二个就是用来开始查找方法开始地方.

说白了,调用方法[super run]在开始找run方法的时候,首先是从父类的类对象(GDPerson)开始找!消息接收者还是self(GDStudent)这个结论应该很清楚吧;

结论

调用super方法的时候,是首先从父类的类对象开始查找方法,消息接收者还是当前类.

好了,知道这个结果,我们继续去看面试题,大家猜一下这两个结果是啥?

// NSLog(@"%@",[super class]);

// NSLog(@"%@",[super superclass]);

我们先来看一下结果:

结果运行

是不是有很诧异的同学.首先class方法在哪?对于一个oc对象,都有class方法这个是吧,所以class方法在NSObject里面,这里应该是没有什么问题.

现在我们去objc源码再去看一下class和superclass的底层实现,请看下图:

所以到这里我们很清楚,为什么会出现上面的结果:

NSLog(@"%@",[self class]);

NSLog(@"%@",[self superclass]);

NSLog(@"%@",[super class]);

NSLog(@"%@",[super superclass]);

分别是:当前类、当前类的父类、当前类、当前类的父类.

总结[super message]

1.消息接收者仍然是子类对象

2.从父类开始查找方法的实现.

接下来博客我会介绍isKindOfClass和isMemberOfClass区别.(小插曲)

比如你知道下面的结果值吗?

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];

BOOL res2 = [[NSObject class]isMemberOfClass:[NSObject class]];

BOOL res3 = [[GDStudent class]isKindOfClass:[GDStudent class]];

BOOL res4 = [[GDStudent class]isMemberOfClass:[GDStudent class]];

介绍完这个面试题之后会再继续介绍runtime的其他知识点,来继续学习runtime

如果觉得我写得对您有所帮助,请关注我,我会持续更新😄