背景
对于self和super这两个关键字,最初的理解是:想当然的以为与java及c++中的this和super用法一致。然而实际上并非完全如此,我们通过一个例子来说明OC中的self和super的实现原理。
例子
有Man和Person两个类:
Man是Person的子类,在Man类中实现一个方法来打印class方法的值(class方法用来表示方法接收者所在的类)。
最初猜测的打印结果:
Man
Person
实际的打印结果:
为什么是这样呢?
真相
self:类的隐藏参数,指向当前调用方法的类。对于静态方法,self指向类对象;对于实例方法,self指向实例对象。
super:“编译器指示符”,表示从父类中查找成员变量或方法。
那么,[self class]与[super class]这两种调用方式为什么会返回相同的结果呢?这就要谈到objective – C的消息机制了。
在OC中,对象调用方法被称为给对象发送消息,如[self class]表示给self指向的对象发送一个方法名为class的消息。
当调用方法的时候,编译器会将其转化成下面4个方法之一:
objc_msgSend
objc_msgSend_stret
objc_msgSendSuper
objc_msgSendSuper_stret
通过[self methodName]调用时,会转化为 objc_msgSend 或 objc_msgSend_stret;
通过[super methodName]调用时,会转化为 objc_msgSendSuper 或 objc_msgSendSuper_stret。
注:_stret系列表示方法的返回值类型为一个结构体,如CGRect。
objc_msgSend
- 函数定义
* id objc_msgSend(id theReceiver ,SEL theSelector, ...)
参数说明
以[self class]为例:
- 第一个参数是消息接收者,也就是Man类的实例;
- 第二个参数是方法的selector,也就是@selector(class);
- 省略号表示方法的可变参数。
- 函数执行流程
- 从self的类的方法列表中找class这个方法,找到执行3,否则执行2。
- 去其父类的方法列表中找class这个方法,找到执行3,否则执行2。
- 把selector传递给接收者。
objc_msgSendSuper
- 函数定义
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
参数说明
以[super class]为例:- 第一个参数是个结构体
- 第二个参数是方法的selector
struct objc_super {
id receiver; //消息接收者
Class superClass; //该类的父类
};
- 函数的执行流程
- 构建objc_super的结构体,这个结构体的第一个变量receiver为Man,与self相同;第二个成员变量superClass是Person,是self对应类的超类。
- 从superClass代表的类的方法列表中寻找class方法,找到执行3,否则继续向上去父类中找class方法。
- 把selector传递给接收者。
从上面的分析中看出,原来当我们调用[self class]、[super class]时,它们的消息接收者都是一样的,即Men这个类的一个实例,只不过是寻找class方法时有所区别。
小结
OC中的self和super,与c++和java中this和super的用法是有一些异同的.
- 相同点
在类的实例方法中,self表示指向实例对象的指针,可以用来调用该类的成员变量和实例方法;super可以用来调用父类的成员变量和实例方法。- 不同点
- 在类的静态方法中,self和super也可以使用,这时self指向该类对象,可以用来调用该类的静态方法;super可以用来调用父类的静态方法。
- super只是一个”编译器指示符”,表示去父类的方法列表中寻找相应方法。消息接收者始终是调用[super xxx]的那个类对象或类实例对象。