关键区分:
1.self是类隐藏参数,super是预编译指令
2.self 调用本类方法,super 调用父类方法
3.(面试相关)【self class】和【super class】输出是一样
为什么会这样呢,往下看:
self和super底层实现原理:
self 调用方法时,查找方法列表 是从本类为起点出发的;而 super ,则从父类的方法列表中开始找,然后调用父类的这个方法。(这句是关键)
他俩都是消息发送
1.self 调用时, objc_msgSend
函数: id objc_msgSend(id theReceiver, SEL theSelector, ...)
。第 一个参数是消息接收者,第二个参数是调用的具体类方法的 selector,后面是 selector 方法的可变参数。
2.super 调用时,会使用 objc_msgSendSuper
函数:id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一个参数是个objc_super的结构体,第二个参数还是类似上面的类方法的selector
struct objc_super {
id receiver; //即消息的实际接收者。
Class superClass; //指针当前类的父类。
};
当编译器遇到 [super class:]
时,开始做这几个事:
构 建 objc_super 的结构体,这个结构体的第一个成员变量 receiver 就是 子类,和 self 相同。而第二个成员变量 superClass 就是指父类
调用objc_msgSendSuper(super->receiver, @selector(class))
的方法,将这个结构体和 class 的 SEL 传递过去。函数里面在做的事情类似这样:从 objc_super 结构体指向的 superClass 的方法列表开始找class 的 selector,找到后再以 objc_super->receiver 去调用这个 selector
举个🌰:
创建三个有继承关系的类:ClassA->ClassB->ClassC(父->子)
1.classA 、classB、classC 分别都重写了自己的class方法
-(Class)class{
return [ClassC class];
}
打印结果:
- 仅classC实现自己的
-(Class)class
方法结果如下
3.png
总结:
1).superClass 就是父类
2).[self class]和 [super class]查找方法的起始位置不同,但调用者是一样的。
为什要写self = [super init]?
因为在Xcode中,你输入init然后tab就会帮你补全这个方法,以至于我一直都忽略了为什么在[super init]之后还要赋值给self,然后进行判断,其实这和类簇有关系,我们不能保证init的内存和alloc出来的内存是同一块内存,像NSString在alloc和init之后的对象分别是NSPlaceholderString和__NSCFConstantString*造成[super init]之后的内存被改变,所以在[super init]之后是nil,因此我们不能保证alloc和init的是同一块内存,加上这样的判断是为了提高容错性,如果init成功就返回对象,否则返回nil.