前提
面试的时候会不会问到类似的问题:类ClassB继承于类ClassA,这时候在类ClassB的方法中分别打印[self class] 与 [super class]会输出什么?
实践出真知:
有没有被惊艳到?[super class]不应该是ClassA吗?请往下看
Self关键字与Super关键字
self 是类的隐藏的参数,指向当前调用方法的类,另一个隐藏参数是_cmd,代表当前类方法的selector。这里只关注这个self。
super并不是隐藏的参数,它只是一个“编译器指示符”,它和self指向的是相同的消息接收者。不同的是,super告诉编译器,要去调用父类的方法而不是本类里的,super只是指示符的作用没有实际意义。
当使用self调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用super时,则从父类的方法列表中开始找。然后调用父类的这个方法。
实现机制
apple的objcRuntimeRef 上说:
Sending Messages
When it encounters a method invocation, the compiler might generate a call to any of several functions to perform the actual message dispatch, depending on the receiver, the return value, and the arguments. You can use these functions to dynamically invoke methods from your own plain C code, or to use argument forms not permitted by NSObject’sperform...methods. These functions are declared in/usr/include/objc/objc-runtime.h.
objc_msgSend sends a message with a simple return value to an instance of a class.
objc_msgSend_stret sends a message with a data-structure return value to an instance of a class.
objc_msgSendSuper sends a message with a simple return value to the superclass of an instance of a class.
objc_msgSendSuper_stret sends a message with a data-structure return value to the superclass of an instance of a class.
我们只关注objc_msgSend和objc_msgSendSuper两个方法。
当使用[self class]调用时,会使用objc_msgSend的函数,先看下objc_msgSend的函数定义:
id objc_msgSend(id theReceiver, SEL theSelector, ...)
第一个参数是消息接收者,第二个参数是调用的具体类方法的selector,后面是selector方法的可变参数。
以 [self class]为例,编译器会替换成调用objc_msgSend的函数调用,其中theReceiver是self,theSelector是 @selector(class),这个selector是从当前self的class的方法列表开始找的@selector(class),当找到后把对应的 selector传递过去。
而当使用[super class]调用时,会使用objc_msgSendSuper函数,看下objc_msgSendSuper的函数定义:
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一个参数是个objc_super的结构体,第二个参数还是类似上面的类方法的selector,先看下objc_super这个结构体是什么东西:
struct objc_super {
id receiver;
Class superClass;
};
可以看到这个结构体包含了两个成员,一个是receiver,这个类似上面objc_msgSend的第一个参数receiver,第二个成员是记 录写super这个类的父类是什么
拿上面的代码为例,当编译器遇到ClassB中init方法里的[super class]时,开始做这几个事:
1,构建objc_super的结构体,此时这个结构体的第一个成员变量receiver就是ClassB的实例,和self相同。而第二个成员变量superClass就是指类ClassA,因为ClassB的超类就是这个ClassA。
2,调用objc_msgSendSuper的方法,将这个结构体和class方法传递过去。函数里面在做的事情类似这样:从 objc_super结构体指向的superClass的方法列表开始找class的selector,找到后再以 objc_super->receiver去调用这个selector,可能也会使用objc_msgSend这个函数,不过此时的第一个参数 theReceiver就是objc_super->receiver,第二个参数是从objc_super->superClass中找到的selector,源代码汇编核心代码大概是这个意思
ENTRY _objc_msgSendSuper
MESSENGER_START
ldr r9, [r0, #CLASS] // r9 = struct super->class
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver 在这里直接加载真实的receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0, #CLASS] // r9 = struct super->class
ldr r0, [r0, #RECEIVER] // load real receiver 在这里直接加载真实的receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper
里面的调用机制大体就是这样了
由此可以知道,为什么[self class]与[super class]打印结果相同了吧
参考内容:
Apple 之《objc4 》
南峰子的技术博客之《Objective-C Runtime 运行时之一:类与对象 》
Loving_iOS之《iOS经典讲解之[self class]和[super class]的区别 》
GSChan之《iOS中self与super 》