OC笔记 - super底层实现(objc4-723)
super底层实现
1 - 先看代码:有 Student和 Person两个类,继承关系如是 Student -> Person -> NSObject
// - Student.m
1 #import "Student.h" 2 3 @implementation Student 4 5 - (instancetype)init{ 6 self = [super init]; 7 if (self) { 8 9 NSLog(@"[self class] = %@",[self class]); 10 NSLog(@"[self superclass] = %@",[self superclass]); 11 NSLog(@"----------------------"); 12 NSLog(@"[super class] = %@",[super class]); 13 NSLog(@"[super superclass] = %@",[super superclass]); 14 } 15 return self; 16 } 17 18 @end
// - main.m
1 #import2 #import "Person.h" 3 #import "Student.h" 4 int main(int argc, const char * argv[]) { 5 6 Person *p1 = [Person new]; 7 Student *stu1 = [Student new]; 8 9 return 0; 10 11 }
预想的结果:[self class] = Student [self superclass] = Person [super Class] = Person [super superclass] = NSObject
日志输出:self我们不难理解,但是 super和我们预想的不一样!
2 - 底层实现
① 为了了解 super实现原理,我们为 Person、Student新增一个 run方法
// - Person.h
#import@interface Person : NSObject -(void)run; @end
// - Person.m
#import "Person.h" @implementation Person -(void)run{ NSLog(@"Person run......."); } @end
// - Student.h
#import "Person.h" @interface Student : Person -(void)run; @end
// - Student.m
1 #import "Student.h" 2 @implementation Student 3 4 - (instancetype)init{ 5 self = [super init]; 6 if (self) { 7 8 NSLog(@"[self class] = %@",[self class]); 9 NSLog(@"[self superclass] = %@",[self superclass]); 10 NSLog(@"----------------------"); 11 NSLog(@"[super class] = %@",[super class]); 12 NSLog(@"[super superclass] = %@",[super superclass]); 13 } 14 return self; 15 } 16 17 18 -(void)run{ 19 [super run]; 20 NSLog(@"Student run......."); 21 } 22 23 @end
② 接着把 Student.m编译成 C++代码,其中 run方法实现如下
static void _I_Student_run(Student * self, SEL _cmd) { ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run")); NSLog((NSString *)&__NSConstantStringImpl__var_folders_t5_d7bd_spn3hsfdqj994fdm9bh0000gn_T_Student_9b1e3e_mi_5); }
我们把 C++代码精简成 OC风格
1 static void _I_Student_run(Student * self, SEL _cmd) { 2 3 // __rw_objc_super结构体 4 objc_msgSendSuper((__rw_objc_super){ 5 (id)self, 6 (id)class_getSuperclass(objc_getClass("Student")) 7 }, 8 9 sel_registerName("run"));// 同 @selector(run) 10 }
打开 runtime源码,打开 __rw_objc_super
struct objc_super { /// Specifies an instance of a class. __unsafe_unretained _Nonnull id receiver; /// Specifies the particular superclass of the instance to message. #if !defined(__cplusplus) && !__OBJC2__ /* For compatibility with old objc-runtime.h header */ __unsafe_unretained _Nonnull Class class; #else __unsafe_unretained _Nonnull Class super_class; #endif /* super_class is the first class to search */ };
我们继续把 __rw_objc_super精简,有两个成员变量
struct objc_super { __unsafe_unretained _Nonnull id receiver; // 消息接收者 __unsafe_unretained _Nonnull Class super_class; // 父类 };
那么回过头来看我们 run方法的实现,其实就是这样子
static void _I_Student_run(Student * self, SEL _cmd) { // 传入了一个 __rw_objc_super结构体 objc_msgSendSuper((__rw_objc_super){ self,// Student class_getSuperclass(objc_getClass("Student")) // [Person class] }, // 调用 @selector(run) sel_registerName("run")); }
我们看一下 objc_msgSendSuper的参数说明,就知道了 Student中的 run方法中的 [super run]调用的方法是从父类 Person中的 run方法开始调用,但是!它的消息接收者传进的仍然是 self = Student
也就是说我们刚开是的代码其实是这样
1 - (instancetype)init{ 2 self = [super init]; 3 if (self) { 4 5 NSLog(@"[self class] = %@",[self class]); // Student 6 NSLog(@"[self superclass] = %@",[self superclass]); // Person 7 NSLog(@"----------------------"); 8 9 10 NSLog(@"[super class] = %@",[super class]);// Student 11 // 这里的 super是从父类 Person开始调用 class 12 // 我们知道 class是 NSObect中的方法,它会一级级地向上查找直至找到 NSObect的 class方法并调用 13 // 而 class的实现是 -(Class)class{ return object_getClass(self);} 14 // 就是说 [super class] 传入的消息接收者是 Student从未改变 15 // 所以输出的是 Student 16 17 18 NSLog(@"[super superclass] = %@",[super superclass]);// Person 19 // superclass 获取的是 Person类对象 20 // -(Class)superClass{ return object_getSuperClass(object_getClass(self));} 21 // super传入的消息接收者依旧是 self = Student,但是最后返回的是 Person 22 } 23 return self; 24 }
结语
1 - [super message]底层实现
① 消息接收者仍然是子类对象
② 调用方法是从父类中开始查询