iOS面试题:[self class]和[super class]输出的是什么?

@implementation Student : Person
- (instancetype)init
{
    self = [super init];
    if (self) {
        id obj1 = [self class];
        id obj2 = [super class];
        NSLog(@"%@",obj1);
        NSLog(@"%@",obj2);
    }
    return self;
}
@end

id objc_msgSend(id theReceiver, SEL theSelector, ...)

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)

都是输出 Student 。
将Student.m 转换成 Cpp 文件看一下

static instancetype _I_Student_init(Student * self, SEL _cmd) {
 self = ((Student *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"));
 if (self) {


  id obj1 = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
  id obj2 = ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"));
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_hj_pwgsq9614nb0vq4zd315tcx80000gn_T_Student_e7cbc1_mi_0,obj1);
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_hj_pwgsq9614nb0vq4zd315tcx80000gn_T_Student_e7cbc1_mi_1,obj2);

 }
 return self;
}

由此可见 当我们调用[self class] 时候实际上编译器最终给我们转成
objc_msgSend(self,@selector(class)) , 消息的接收者是当前所在类的实例对象 , 这个时候就会去 self 所在类 Student 去查找 class 方法 ,
如果当前类 Student 没有 class 会向Student 父类 Person 类找 class 方法,
如果 Person 类也没有找到 class 方法,最终会找到最顶级父类 NSObject 的 class 方法,
最终找到 NSObject 的 class 方法 ,并调用了object_getClass(self) ,由于消息接收者是 self 当前类实例对象,
所以最终 [self class]输出 Student

那么为什么明明调用了 super 这个关键字 返回的[super class] 还是 Student 呢 ?
通过上边代码可知 , [super class] 最终编译器转化成了 objc_msgSendSuper(struct objc_super *,SEL) ,其中

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};
#endif

objc_super 是一个结构体,内部有一个 receiver 实例,和一 个 Class super_class,指向了当前类的父类 Class ,通过这个父类可以直接的从父类里边开始查找方法,由于消息接收者还是当前类的实例对象 self, 最终如果在父类中没有找到class 这个方法,会在 Person 类的父类 NSObject 中去查找 class 方法,由于 NSObject 的 class 方法,调用的是 object_getClass(self) ,所以最终消息接收者为 student 实例对象,所以返回的还是 Student .

刚才情况都是 super Person 没有 class 方法,如果 Person 重写了 class 方法呢?


1155481-4dbe0e65fe7c8931.png

当我们在 Student init 方法中调用 [super class] 时候 ,它首先会到 Person 类中查找 class 方法 ,当它发现了 Person 实现了 class 方法,就会调用[person class] 方法, 这个时候 object_getClass(self), 这个 self 是 Student 的实例对象,就是消息接收者,所以即使重写了 Person 的 class 方法 ,依然返回的还是 Student ,除非 把 class 方法实现返回nil , 这样最终调用[super class]结果才会返回nil.

综合以上分析,当输出[self class]和[super class]的过程就是一下:

当使用[self class]时,这时的self是Student,在使用objc_msgSend时,第一个参数是receiver也就是self,也是 Student * student这个实例。第二个参数,要先找到class这个方法的selector,先从Student这个类开始找,没有,然后到父类 Person中去找,也没有,再去Father的父类NSObject去找,一层一层向上找之后,在NSObject的类中发现这个class方法,而 NSObject的这个class方法,就是返回receiver的类别,所以这里输出Student。

当使用[super class]时,这时要转换成objc_msgSendSuper的方法。先构造objc_super的结构体吧,第一个成员变量就是self, 第二个成员变量是Person,然后要找class这个selector,先去superClass也就是Father中去找,没有,然后去Person 的父类中去找,结果还是在NSObject中找到了。然后内部使用函数objc_msgSend(objc_super->receiver, @selector(class)) 去调用,此时已经和我们用[self class]调用时相同了,此时的receiver还是Student* student,所以这里返回的也是Student。

你可能感兴趣的:(iOS面试题:[self class]和[super class]输出的是什么?)