iOS 底层小记三 self和super的真相

1,036 阅读1分钟

先从一段代码说起:


@interface Person : NSObject
@end
@implementation Person
@end

@interface Son : Person
@end
@implementation Son

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSLog(@"%@", [self class]);
        NSLog(@"%@", [super class]);
    }
    return self;
}

@end

/// 打印结果:
Son
Son
都是Son

使用 clang -rewrite-objc 这个命令后,得到的中间代码有如下关键部分:

(void *)objc_msgSend)((id)self, sel_registerName("class")

(void *)objc_msgSendSuper)((__rw_objc_super){ (id)self, (id)class_getSuperclass(objc_getClass("Son")) }, sel_registerName("class")

从上述C++源码可以看出,[self class][super class]的区别只是: objc_msgSend(id, SEL)objc_msgSendSuper(__rw_objc_super *superclass, SEL) 的区别, 只是查找方法的起点不一样,前者是当前类Son,后者是父类Person

objc_msgSendSuper最终也会转为objc_msgSend( (id)self, sel_registerName("class"))

那不就是普通的消息发送的流程么,前者从Son开始找class方法,后者从父类Person开始找,由于两者都没有class方法,两者都来到基类NSObject,都调用基类的class方法。

查看runtime源码:

// NSObject.mm
-(Class)class { 
  return object_getClass(self); 
}

// objc-class.mm
Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

所以,其实两者都是去找selfisa指针指向的类对象,也就是Sonsuper只是一个编译指令,其实消息接收者还是self, 也就是当前类的实例对象。

  • 补充,为什么对象在初始化的时候,需要self = [super init]? 其实也是等于调一下父类的init方法,把父类的初始化数据带过来,写入到当前类的内存空间里,再交给当前类的实例对象。