Runtime ---- super的本质

如果您希望拥有更好的阅读体验,欢迎访问 我的开发笔记


一道面试题引发的,对于super本质的探究
@implementation RTStudent

-(instancetype)init {
	if (self = [super init]) {
		NSLog(@"self和super调用class的结果:");
		NSLog(@"[self class]---%@",[self class]);
		NSLog(@"[super class]---%@",[super class]);
		
		NSLog(@"self和super调用superclass的结果:");
		NSLog(@"[self superclass]---%@",[self superclass]);
		NSLog(@"[super superclass]---%@",[super superclass]);
	}
	return self;
}

@end

下边的代码打印的是什么?

int main(int argc, const char * argv[]) {
	@autoreleasepool {
		__unused RTStudent *stu = [[RTStudent alloc] init];
	}
	return 0;
}

结果如下

self和super调用class的结果:
[self class]---RTStudent
[super class]---RTStudent

self和super调用superclass的结果:
[self superclass]---RTPerson
[super superclass]---RTPerson

为什么是这样的结果呢?super到底是怎么来发消息的?做一个测试:

@implementation RTStudent
-(void)run{
	[super run];
	NSLog(@"RTStudent--run");
}
@end

运行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc RTStudent.mRTStudent.m转为c++文件,去掉打印和类型强转后为:

static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {
 objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("RTStudent"))}, sel_registerName("run"));
}

第一个参数是个结构体,再次抽取后:

static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {

__rw_objc_super arg = {
(id)self,
(id)class_getSuperclass(objc_getClass("RTStudent"))
}
objc_msgSendSuper(arg, sel_registerName("run"));
}

将runtime函数转为oc:

class_getSuperclass(objc_getClass("RTStudent")) ==> [RTPerson class]

sel_registerName("run") ==> @selector(run)

最终为:

static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {

__rw_objc_super arg = {self, [RTPerson class]}
objc_msgSendSuper(arg, @selector(run));
}

在runtime源码中找到objc_super结构体定义:

/// Specifies the superclass of an instance. 
struct objc_super {
id receiver; //消息接受者
Class super_class; //消息接受者父类
};

objc_msgSendSuper方法定义为:

objc_msgSendSuper(struct objc_super * super, SEL op, ...)

有文档including the instance of the class that is to receive the message and the superclass at which to start searching for the method implementation可知方法的接收者为结构体中的receiver,查找方法的时候从结构体中的super_class开始,而clas的方法实现为

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

所以object_getClass(self)中的self就是objc_super这个结构体中的receiver,所以[self class]会和[super class]的一样

以上只是转为c++代码的分析,实际通过打断点查看汇编代码发现,调用的函数是objc_msgSendSuper2(源码在objc-msg-arm64.s文件中,查看函数实现)

    0x100000c0c <+28>: movq   0x6d5(%rip), %rsi         ; (void *)0x0000000100001340: RTStudent
    0x100000c13 <+35>: movq   %rsi, -0x18(%rbp)
    0x100000c17 <+39>: movq   0x69a(%rip), %rsi         ; "run"
    0x100000c1e <+46>: movq   %rax, %rdi
    0x100000c21 <+49>: callq  0x100000e54               ; symbol stub for: objc_msgSendSuper2
    0x100000c26 <+54>: leaq   0x41b(%rip), %rax         ; @"RTStudent--run"

而且传入的结构体是objc_super2

struct objc_super2 {
    id receiver;
    Class current_class;
};

可以看到第二个变量变为current_class了,那么查找方法时会在当前类对象里查找吗?

ldr	p16, [x16, #SUPERCLASS]	// p16 = class->superclass

objc_msgSendSuper2源码中,发现这句注释class->superclass,所以最终它还是会直接从父类对象中查找方法

Runtime源码地址


如果您希望拥有更好的阅读体验,欢迎访问 我的开发笔记


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值