[self class] 与 [super class]

语言: CN / TW / HK
@implementation Son : Father
- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end
// 运行结果:
2016-04-17 14:21:36.060 Test[8566:568584] NSStringFromClass([self class]) = Son 2016-04-17 14:21:36.061 Test[8566:568584] NSStringFromClass([super class]) = Son

self 是类的隐藏参数,指向当前调用方法的这个类的实例。

super 是一个 Magic Keyword , 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者。而不同的是, super 是告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。

上面的demo中不管调用 [self class] 还是 [super class] ,最终的接受消息的对象都是当前 Son 这个对象。

当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;

当使用 super 时,则从父类的方法列表中开始找。

通过 clang 命令验证:

clang -rewrite-objc test.m

从上面的代码中,我们可以发现当在调用 [self class] 时,会转化成 objc_msgSend 方法。看下方法定义:

id objc_msgSend(id self, SEL op, ...)

而在调用 [super class] 时,会转化成 objc_msgSendSuper 方法。看下方法定义:

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

查看 objc_super 结构体发现:

OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )


/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained 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 Class class;
#else
    __unsafe_unretained Class super_class;
#endif
    /* super_class is the first class to search */
};

objc_super 结构体有两个成员:

  • 第一个成员是接收消息的 receiver , 类似于上面的 objc_msgSend 方法第一个参数 self
  • 第二个成员是当前类的父类 super_class

所以,当调用 [self class] 时,实际先调用的是 objc_msgSend 方法,第一个参数是接收消息的 receiver 也就是 Son 当前的这个实例,然后在 Son 类的方法列表开始查找 selector ,如果没有,则去父类的方法列表开始查找 selector ,如果父类里面也没有,则会在 NSObject 查找方法列表开始查找 selector ,找到后以 self 去调用父类的这个 selector

objc Runtime 开源代码对 - (Class)class 方法的实现:

- (Class)class {
  return object_getClass(self);
}

- (Class)class 的实现就是返回 self 自己,故上述输出结果为 Son

而当调用 [super class] 时,会转换成 objc_msgSendSuper 方法:

  • objc_super 结构体指向的 superClass 父类的方法列表开始查找 selector ,找到后以 objc->receiver 去调用父类的这个 selector
  • 由于找到了父类 NSObject 里面的 class 方法的 IMP ,又因为传入的入参 objc_super->receiver 指向 selfself 也就是 Son 当前的这个实例,所以父类的方法 class 执行 IMP 之后,输出还是 Son
    最后输出两个都一样,都是输出 Son