美文网首页
iOS底层-self、super、superclass

iOS底层-self、super、superclass

作者: Engandend | 来源:发表于2019-12-18 18:45 被阅读0次

    基本理解:

    • self : 当前方法的调用者
    • super:不是一个指针,编译指示器(标识符),在程序编译时内部会做一些特殊处理 (底层会被编译成 objc_msgSendSuper()方法)
    • superclass:是一个方法,返回的结果是调用者的父类对象

    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;
    }
    
    

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

    • 1、调用[self class]的时候,底层是调用的 objc_msgSend(....)
    • 2、调用[super class]的时候,底层调用的是 objc_msgSuperSend(....)
    • 3、super调用的方法,从父类开始查找[class_getSuperclass(...)]

    知道了调用的方法之后,我们从底层源码源码页面中搜索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

    • 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);
        }
    
    .......
    }
    

    相关文章

      网友评论

          本文标题:iOS底层-self、super、superclass

          本文链接:https://www.haomeiwen.com/subject/ifeunctx.html