super关键字

super作用

当我们创建好一个默认的controller,Xcode帮我们自动生成一些默认代码,其中就有super:

#import "ViewController.h"

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
@end
复制代码

我们都知道[super viewDidLoad]是为了调用父类方法,以此为基础调用子类的一些方法,来实现功能需求.

super本质

在了解本质之前,我一直理解的super就是代表父类,可能底层实现就是class_getSuperclass()函数,然后配合msgSend函数调用.
然而,事实不是如此.
我们先将上述代码转换为C/C++代码:

static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self,
        (id)class_getSuperclass(objc_getClass("ViewController"))
    }, sel_registerName("viewDidLoad"));
}
复制代码

将强制转换等优化一下:

objc_msgSendSuper(
    {   (id)self,
        (id)class_getSuperclass(objc_getClass("ViewController"))
    },
     sel_registerName("viewDidLoad"));
复制代码

很明显,super的调用和我们预想的不太一样,调用函数是objc_msgSendSuper,第一个参数是结构体包含了selfsuperClass,第二个参数是SEL

虽然转换的是objc_msgSendSuper,但是我们断点显示的是objc_msgSendSuper2方法,也就是说实际底层调用的是带数字2的函数,我们查找objc源码 :

断点:

super关键字.png

源码解读并添加注释:

/********************************************************************
 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
 *
 * struct objc_super {
 *     id receiver; // 消息接收者.[self]
 *     Class cls;	// SUBCLASS of the class to search .[当前类]
 * }
 ********************************************************************/
	
	ENTRY _objc_msgSendSuper2
	
	ldr	r9, [r0, #CLASS]	// class = struct super->class,取出传入的cls
	ldr	r9, [r9, #SUPERCLASS]   // class = class->superclass,取出cls的父类
	CacheLookup NORMAL, _objc_msgSendSuper2 // 从cls的父类中开始查找方法,先从缓存中查找,找到就调用,真正的调用者是传入的结构体的第一个成员`self`.
	// cache hit, IMP in r12, eq already set for nonstret forwarding
	ldr	r0, [r0, #RECEIVER]	// load real receiver
	bx	r12			// call imp
        
        // 如果没有在缓存中找到,就去方法列表中查找,真正的调用者是传入的结构体的第一个成员`self`
	CacheLookup2 NORMAL, _objc_msgSendSuper2
	// cache miss
	ldr	r9, [r0, #CLASS]	// class = struct super->class
	ldr	r9, [r9, #SUPERCLASS]   // class = class->superclass
	ldr	r0, [r0, #RECEIVER]	// load real receiver
	b	__objc_msgSend_uncached
	
	END_ENTRY _objc_msgSendSuper2
复制代码

结论

  • super的调用,底层会转换为_objc_msgSendSuper2函数的调用,接收两个参数:

* id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
*
* struct objc_super {
*     id receiver; // 消息接收者.[self]
*     Class cls;	// SUBCLASS of the class to search .[当前类]
* }
复制代码
  • receiver是消息接收者,cls决定了从哪里开始查找方法(cls->superClass)

  • 通过编译转换的代码不一定是真正的执行代码,但实际八九不离十.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享