Cx330

「重学iOS」Objective-C中super的相关内容

2020-12-19 · 4 min read
runtime Objective-C iOS

首先我们来看一下这段代码:

01.png

我们发现最终的打印结果和我们预期的不一样,按我们的思路Super就是指的的Dog的父类Animal,Animal调用class方法应该返回Animal 但是结果却不是这样,这是为什么?首先我们先将这段代码转换成c++底层代码来一探究竟:

static instancetype _I_Dog_init(Dog * self, SEL _cmd) {
    self = ((Dog *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Dog"))}, sel_registerName("init"));
    if (self) {
        // NSLog(@"%@",[self class]);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_f1_q0392lf551qfbg1b5sy48qb80000gn_T_Dog_db6ed5_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")));
        
       //NSLog(@"%@",[self superclass]);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_f1_q0392lf551qfbg1b5sy48qb80000gn_T_Dog_db6ed5_mi_1,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass")));
        
        //NSLog(@"%@",[super class]);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_f1_q0392lf551qfbg1b5sy48qb80000gn_T_Dog_db6ed5_mi_2,((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Dog"))}, sel_registerName("class")));
        
        //NSLog(@"%@",[super superclass]);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_f1_q0392lf551qfbg1b5sy48qb80000gn_T_Dog_db6ed5_mi_3,((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Dog"))}, sel_registerName("superclass")));
    }
    return self;
}

将上述代码简化后得到下面的结果:

02.png

我们发现,当self调用class方法时,是执行的**objc_msdSend(self,@selector(class))**函数,消息的接收者是当前所在类的实例对象(Dog) , 这个时候就会去self所在类 Dog去查找class方法 , 如果当前类Dog没有class方法会向其父类Animal类找 class 方法, 如果Animal类也没有找到class方法,最终会找到最顶级父类NSObject的class方法, 最终找到NSObject的class方法 ,并调用了object_getClass(self) ,由于消息接收者是 self 当前类实例对象, 所以最终 [self class]输出Dog(class方法是返回方法调用者的类型,superclass方法是返回方法调用者的父类)

[self superclass] 也是同理,找到superclass方法,然后返回调用者的父类,即Animal;

但是当我们调用super的class方法时,底层不是转换成objc_msdSend而是变成了objc_msgSendSuper函数。这个函数有两个参数,第一个参数是个结构体,结构体中有两个成员:方法调用者和调用者的父类,第二个参数就是方法名,也就是class方法的SEL。

[super class] ->
objc_msgSendSuper(
                  //第一个参数:结构体
                  {self,//方法调用者
                   class_getSuperclass(objc_getClass("Dog"))//当前类的父类
                  },
                  //第二个参数:方法名
                  sel_registerName("class")));

所以,我们看到[self class]和[super class],他们转换成的底层实现都不一致。objc_msgSendSuper函数的作用是告诉方法调用者去其父类中查找该方法,也就是相比objc_msdSend函数而言少了去自己类中查找方法这一步,而是直接去父类中找class方法,但是方法调用者还是没变,都是Dog。class方法和superclass它们都是返回方法调用者的类型或父类,所以[super class]和[super superclass]还是返回的Dog的类型和父类,所以打印结果是Dog和Animal,与[self class]和[self superclass]结果一致。

所以,总结起来就是,super方法底层会转换为objc_msgSendSuper函数的调用,这个函数的作用是告诉方法调用者去父类中查找方法