iOS-浅谈OC中的Super关键字

2019-05-17  本文已影响0人  晴天ccc

目录

  • super关键字
    ----问题思考
    ----super的结构
    ----objc_super结构体
    ----class方法的底层实现
    ----superclass方法的底层实现
  • 总结
    ---- [super class] 总结
    ---- [super superclass] 总结
  • 补充

super关键字

创建Person类和其子类Student。在Student内部添加如下代码,观察两组打印结果:

NSLog(@"第一组----------");
NSLog(@"[self class] %@", [self class]);
NSLog(@"[self superclass] %@", [self superclass]);

NSLog(@"第二组----------");
NSLog(@"[super class] %@", [super class]);
NSLog(@"[super superclass] %@", [super superclass]);

打印结果:

第一组----------
[self class] Student
[self superclass] Person
第二组----------
[super class] Student
[super superclass] Person

如果super代表的是父类,那么为什么selfsuper调用class的结果相同?

PersonStudent都添加run方法。
Student执行run方法时调用父类run方法。

- (void)run {
    [super run];
}

转成C++代码:

((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));

整理一下:

struct objc_super sp = {
    self,
    [Person class],
};
objc_msgSendSuper(sp, @selector(run));

可以看到使用super关键字调用方法时,底层使用的是objc_msgSendSuper方法,且传入参数为objc_super结构体和SEL

objc_super的结构如下,包含消息接收者和消息接收者的父类两个成员:

struct __rw_objc_super { 
    struct objc_object *object; // 消息接收者
    struct objc_object *superClass; // 消息接收者的父类,决定了方法从那个类开始查找。
};

通过 objc源码 message.hobjc_msgSendSuper方法注释可知,当调用方法时会先在superClass中开始搜索方法实现。

class方法是在NSObject内部实现的,源码:

- (Class)class {
    return object_getClass(self);  
}

返回消息接收者(对象)的具体类型

superclass方法是在NSObject内部实现的,源码:

- (Class)superclass {
    return class_getSuperclass(object_getClass(self));
}

返回消息接收者(对象)父类的class。

总结

  • super调用方法,在底层实际上是通过objc_msgSendSuper方法实现。
  • 传入的参数是一个objc_super结构体。
  • objc_super结构体的第一个参数是self,最终消息接收者
  • 先从传入的第二个参数是消息接收者的父类,所以从该父类开始查找方法的实现
  • 最终在NSObject中查到到方法class,进行调用。
  • 返回消息接收者(对象)的具体类型。

所以打印[super class]结果是Student

  • 最终在NSObject中查到到方法superclass,进行调用。
  • 返回消息接收者(对象)父类的class。

所以打印[super superclass]结果是Person

补充

将super调用转成C++代码后,显示的底层实现是objc_msgSendSuper方法,但真实的底层方法是objc_msgSendSuper2
可以通过汇编代码查看。

0x100003f2e <+46>: callq  0x100003f4c   ; symbol stub for: objc_msgSendSuper2
callq   _objc_msgSendSuper2

由此可见,super真实底层实现是_objc_msgSendSuper2方法。

上一篇 下一篇

猜你喜欢

热点阅读