前言
本文涉及到的源码环境为objc4-818.2
我们在初始化方法中无数次用到了self和super,我们今天就对他们做一下研究。
- 创建类
Father继承自NSObject - 创建类
Son继承自Father 
@implementation Son
-(instancetype)init{
    if (self  = [super init]) {
        NSLog(@"1 -- %@",[self class]);
        NSLog(@"2 -- %@",[super class]);
    }
    return self;
}
@end
输出结果
1 -- Son
2 -- Son
1打印出当前Son没有问题,那为什么2不输出Son的父类Father呢????- 为什么
[super init]返回子类实例对象而不是父类实例对象??? 
self
在源码环境的NSObject.mm中查看class方法的实现
- (Class)class {
    return object_getClass(self);
}
Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
inline Class
objc_object::getIsa() 
{
    // 我们研究普通对象
    if (fastpath(!isTaggedPointer())) return ISA();
    ......
}
inline Class
objc_object::ISA(bool authenticated)
{
    ASSERT(!isTaggedPointer());
    return isa.getDecodedClass(authenticated);
}
inline Class
isa_t::getDecodedClass(bool authenticated) {
    ...
    return getClass(authenticated);
}
inline Class
isa_t::getClass(MAYBE_UNUSED_AUTHENTICATED_PARAM bool authenticated) {
    ...
    uintptr_t clsbits = bits;
    ...
    clsbits &= ISA_MASK;
    ...
    return (Class)clsbits;
}
我们前文学过nonpointer对象的isa指针包含指向类对象的指针,以上过程就是从实例对象的isa取出类指针的过程。
对于class方法我们可能比较好奇他访问的self为什么不是NSObject呢??
- (Class)class {
    // 这里访问的self是谁??
    return object_getClass(self);
}
我们知道函数的执行在OC底层是通过objc_msgSend进行消息发送完成的,objc_msgSend有两个默认参数self和_cmd
self为消息接收者_cmd为函数名...后面为参数
id objc_msgSend(id self, SEL _cmd, ...);
同样在函数中也有默认参数self和_cmd,他们和objc_msgSend中的默认参数相对应,可简单理解为
- (Class)class(id self, SEL _cmd) {
    ......
}
因为我们在自定义类Father和Son中都没有实现class方法,所以消息查找流程会顺着继承链查找到NSObject中的class方法,但是self对象依然是Son的实例对象。
我们再举一个小例子,在父类Father中实现方法fatherMethod
@interface Father : NSObject
- (void)fatherMethod;
@end
@implementation Father
- (void)fatherMethod{
    NSLog(@"self == %@",self);
}
@end
在子类Son中没有实现任何方法,我们用子类的实例对象来调用fatherMethod方法
int main(int argc, char * argv[]) {
@autoreleasepool {
        Son *son = [[Son alloc] init];
        [son fatherMethod];
}
    return 0;
}
执行结果为
self == <Son: 0x28211c140>
无论方法在哪里实现,方法中访问的self都是消息接收者。
super
self是消息接收者,是消息发送函数objc_msgSend的默认参数之一。super就没那么简单了,他不是一个参数而是一个编译器的关键字。我们在Son.m中实现
@implementation Son
-(instancetype)init{
    if (self  = [super init]) {
        NSLog(@"%@",[super class]);
    }
    return self;
}
@end
我们通过clang和汇编两种方式来探索其底层原理
通过clang查看其底层实现
终端进入Son.m路径执行命令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Son.m
可以看到Son.cpp文件中[super class]的底层实现为
struct __rw_objc_super { 
    struct objc_object *object; 
    struct objc_object *superClass; 
    __rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {} 
};
......
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"))
消息发送是通过objc_msgSendSuper而不是objc_msgSend,消息接收者变成了__rw_objc_super结构体指针
通过汇编查看
不同的是这里执行了
objc_msgSendSuper2
源码探索
我们带着这些疑问来进入底层的世界
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
这两个函数的参数是一样的,有两个默认参数
objc_super类型的superSEL类型的op- 参数们
 
objc_super结构为(objc2环境)
struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
    /* super_class is the first class to search */
};
备注写的清楚,方法查找时super_class是第一个查找的class
在objc-msg-arm64.s文件中搜索objc_msgSendSuper和objc_msgSendSuper2的实现
ENTRY _objc_msgSendSuper
// 跳转到L_objc_msgSendSuper2_body中继续执行 
b L_objc_msgSendSuper2_body
END_ENTRY _objc_msgSendSuper
ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame
 
// 和objc_msgSend不同的是p16不是指向class而是指向superclass
ldp p0, p16, [x0] 
ldr p16, [x16, #SUPERCLASS]  
L_objc_msgSendSuper2_body:
CacheLookup NORMAL, _objc_msgSendSuper2, __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2
和objc_msgSend不同的是p16不是指向class而是指向superclass,但是消息接收者receiver是一样的,验证一下。
在父类Father中定义和实现方法fatherMethod和method
@interface Father : NSObject
- (void)fatherMethod;
- (void)method;
@end
@implementation Father
- (void)fatherMethod{
    NSLog(@"self == %@",self);
}
- (void)method{
    NSLog(@"father-method");
}
@end
在子类Son中重写fatherMethod方法并实现method方法
@interface Son : Father
- (void)method;
@end
@implementation Son
- (void)fatherMethod{
    [super fatherMethod];
    [super method];
}
- (void)method{
    NSLog(@"son-method");
}
@end
运行之
int main(int argc, char * argv[]) {
    @autoreleasepool {
        Son *son = [[Son alloc] init];
        [son fatherMethod];
    }
    return 0;
}
执行结果
self == <Son: 0x2806b8130>
father-method
[super fatherMethod]中消息接收者依然是子类Son的实例对象,所以fatherMethod中访问到的self为Son的实例对象
虽然子类Son也实现了method方法,但是[super method]是从父类Father开始查找的
小结
self调用方法[self xxx]和super调用方法[super xxx]
- 相同点为:消息接收者
receiver是一样的 - 不同点为:
[super xxx]会从父类开始消息查找流程 
-(instancetype)init{
    if (self  = [super init]) {
        ......
    }
    return self;
}
+ (id)init {
    return (id)self;
}
[super init]从父类开始查找init函数,但是消息接收者依然是子类实例对象,所以在init函数中访问并返回的self为子类实例对象。