iOS底层-self、super、superclass

2019-12-18  本文已影响0人  Engandend

基本理解:

super 的作用只是告诉编译器,查找方法的时候不用找自己的方法列表,直接从父类开始找。(调用者还是我自己)
我们在研究方法查找流程的时候知道,发送消息是先找自己的方法,然后递归找父类的方法, 而super就是告诉编译器,不要从我这找了,直接从父类开始找吧。

每当讲解self与super的时候,都会拿这个经典的代码示例来做说明:

// 背景  Person:NSObject     Student:Person

//重写Student的init方法
- (instancetype)init
{
    if (self = [super init]) {
        NSLog(@"self = %@",NSStringFromClass([self class]));
        NSLog(@"super = %@",NSStringFromClass([super class]));
    }
    return self;
}

//初始化Studen([Student new])  打印结果
self = Student
super = Student    
/**
⚠️ 如果 定义一个Student子类 : StudentChild : Student
子类  StudentChild 不重写 init方法  
执行  [StudentChild  new];
那么这里打印的  是 

self = StudentChild
super = StudentChild    
*/

⚠️:self 和 super 都是调用者
Sutdent 调用init 那么 self、super 就是Student
StudentChild 调用init 那么 self、super 就是StudentChild

按照一般人的想法:这里的super 应该是Person,而实际上却是Student,那是因为 在理解super之前容易将super 和 superclass混淆

从源码来分析self、super

上面有说到:super 是 编译指示器(标识符) 而不是指针,self是方法调用者,是一个指针
⚠️ 只要记住super 不是 superclass,理解super就很容易了

我们从汇编代码来看看,他究竟干了什么

cd 到Student.m的上一级目录,然后通过命令:

clang -rewrite-objc Student.m

// 或者  
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m -o out.cpp  (Student.m 是需要转换的文件  out.cpp 是转换之后的名字,也可以省略,默认原来的名字(从-o 开始省略))

可以找到这样一段底层代码


static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = ((Student *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_0,NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_1,NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
    }
    return self;
}

//简化之后
static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = ((Student *(*)objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
        NSLog(NSStringFromClass(objc_msgSend)((id)self, sel_registerName("class"))));
        NSLog(NSStringFromClass(objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
    }
    return self;
}

从简化之后的代码能看以下信息

知道了调用的方法之后,我们从底层源码源码页面中搜索objc
来分析:

OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )

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

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};

objc_msgSend相对比较好理解,对应到这里,[self class] 就是 objc_msgSend(调用者(self),调用方法(@selecter(class)),....(其他参数))

[super class] 中 objc_msgSendSuper() 的参数是一个objc_super结构体 结构体的第一个参数和objc_msgSend一样,也是receive(self),只是通过第二个参数 super_class 知道,方法从父类去找

可以理解为 objc_msgSendSuper(调用者(self),从哪开始找(super_class),调用方法(@selecter(class)),....(其他参数))

self 再探

上面说了super的理解,接下来对self梳理一遍

// 背景  Person:NSObject     Student:Person

//Person 声明并实现 readBook方法
//Person.h
- (void)readBook;

//Person.m
- (void)readBook
{
    NSLog(@"person readBook  self = %@",NSStringFromClass([self class]));
}

//Student 重写readBook
- (void)readBook
{
    [super readBook];
    NSLog(@"Student readbook");
}

//初始化Studen 并调用readBook
Student *s = [Student new];
 [s readBook];

//先思考答应结果,再看运行结果

//打印结果
person readBook  self = Student
Student readbook

上面的代码中,在Person中的[self class] 中的self 依然是Student,因为最开始就说过,self是调用者,在这里 是student调用了 readBook,所以,即使[self class]在Person,依然是Student

superclass

+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

掉用superclass就是获取对象所在类的superclass 从对象本质(结构体)中看:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;        //  <-----⚠️  就是它
    cache_t cache; 
    class_data_bits_t bits;

    class_rw_t *data() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

.......
}
上一篇下一篇

猜你喜欢

热点阅读