20 / 12 / 19

「重学 OC」内存管理07 - Objective-C中super的相关内容

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

我们发现最终的打印结果和我们预期的不一样,按我们的思路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; }

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

我们发现,当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函数的调用,这个函数的作用是告诉方法调用者去父类中查找方法