我们在OC中经常遇见self和super,那接下来我看按照我们自己的思路,那么接下来我们看代码:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"self class%@", NSStringFromClass([self class]));
NSLog(@"super class%@", NSStringFromClass([super class]));
}
结果:
我们想象的结果是:
2017-11-24 14:14:19.173506+0800 objectClass_dyn[75423:12940896] self class ViewController
2017-11-24 14:14:19.173703+0800 objectClass_dyn[75423:12940896] super class UIViewController
因为我们理解的[super class]是调用父类的方法,应该是ViewController的父类UIViewController调用的方法.
但是世界的结果是:
2017-11-24 14:14:19.173506+0800 objectClass_dyn[75423:12940896] self class ViewController
2017-11-24 14:14:19.173703+0800 objectClass_dyn[75423:12940896] super class ViewController
此处的表情是:
为什么会是这样呢?住不符合人类伦理道德啊!
那事实的真相只有一个,就是---
电脑抽风,那是不可能的。
那么真相就是:
self 是类的隐藏参数,指向所调用方法的类。那super是啥?super只是一个‘编译器指示符’,它和self指向相同的消息的接收者,所以不管是[self class]还是[super class],接收消息的对象都是ViewController。super 和self的不同之处是,super告诉编译器在调用class方法的同时要去父类调用方法,而不是从本类中。
此时你也许还有这样的疑问,对啊,super是去父类中调用了啊,为什么不是父类的对象。
当我们使用self调用方法的时候,先在本类的方法列表中查找,没有,才会去父类中寻找;但是使用super的时候,则直接从父类的方法列表中查找,然后调用这个方法。
那么接下来我们看一下:
使用clangg改造ViewController.m这个文件
clang -rewrite-objc ViewController.m
会发现上面的调用变成了:
NSLog((NSString *)&__NSConstantStringImpl__var_folders_14_p0_xgk8d7z746b5mfwnz78x80000gn_T_ ViewController_0aad65_mi_1, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_14_p0_xgk8d7z746b5mfwnz78x80000gn_T_ ViewController_0aad65_mi_2, NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("class"))));
可以看到[self class]调用时,会被转化成objc_msgSend形式,而objc_msgSend的定义是:
void objc_msgSend(void /* id self, SEL op, ... */ )
我们把self作为第一个参数传入。
而我们在调用[super class]的时候,会被转化成objc_msgSendSuper形式,而objc_msgSendSuper的定义是:
void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
函数的第一个参数是一个名叫super的objc_super类型的结构体指针,那么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 */
};
#endif
根据上面的宏的条件编译,实际上只存在两个参数receiver和super_class,前一个参数receiver类似于objc_msgSend函数的第一个参数self,要求是指定类的实例;第二个参数super_class,当前类的父类。
所以调用[self class]的时候,实际调用的objc_msgSend函数,第一个参数是ViewController这个类的实例,然后在ViewController这个类中找-(Class)class 这个方法,没找到去父类(UIViewController)找,也没有最后在NSObject找,而-(Class)class的实现就是返回self的类别,所以上述输出的结果为ViewController。
runtime中-(Class)class的实现:
-(Class)class{
return object_getClass(self);
}
当调用[super class]时,会转换成objc_msgSendSuper函数,第一步是构建objc_super结构体,结构体的第一个成员便是ViewController的实例self,第二个成员变量是(id)class_getSuperclass(objc_getClass("ViewController")),便是ViewController的父类UIViewController。第二步是去UIViewController中寻找-(Class)class 这个函数,没有,然后去NSObject类中找,找到了,最后内部使用objc_msgSend(objc_super->receiver, @selector(class))去调用,此时和[self class]调用相同,还是返回ViewController。
总结:self和super 在调用的时候都是当前类或者类的实例去调用本身的方法或者父类的方法,用OC的语言来解释就是发送消息的对象都是当前的类或者当前类的实例。
简单的描述:
class A: B;
在A中:
[self class]; A或者A的实例对象调用本身的方法,调用方法的主体是类A或者A的对象。
[super class];A或者A的实例对象调用父类的方法,调用方法的主体是类A或者A的对象。
两个方法的调用的主体是没有变的,只是调用的方法是本身还是父类的区别。