-
案例
新建一个类 Father
@interface Father : NSObject
@end
#import "Father.h"
@implementation Father
@end
新建一个类Son,继承Father
@interface Son : Father
@end
#import "Son.h"
@implementation Son
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"%@",NSStringFromClass(self.class));
NSLog(@"%@",NSStringFromClass(super.class));
NSLog(@"%@",self.class);
NSLog(@"%@",super.class);
/**
2019-01-11 23:19:08.786280+0800 super与self[1501:29323] Son
2019-01-11 23:19:08.786455+0800 super与self[1501:29323] Son
2019-01-11 23:19:08.786575+0800 super与self[1501:29323] Son
2019-01-11 23:19:08.786667+0800 super与self[1501:29323] Son
*/
}
return self;
}
@end
调用
Son *son = [[Son alloc] init];
输出结果:
2019-01-11 23:19:08.786280+0800 super与self[1501:29323] Son
2019-01-11 23:19:08.786455+0800 super与self[1501:29323] Son
--
2019-01-11 23:19:08.786575+0800 super与self[1501:29323] Son
2019-01-11 23:19:08.786667+0800 super与self[1501:29323] Son
- 分析
- self 是类的隐藏参数,指向当前调用方法的这个类的实例。
而 super 是一个 Magic Keyword, 它本质是一个编译器标示符
或者说是编译器指令
,和 self 是指向的同一个消息接受者,也就是说【self本身就是一个强指针,而super不是, super本质上还是子类对象本身,而不是父类对象,super是告诉编译器,调用 class 这个方法时,要去父类的方法中去寻找,而不是本类里寻找】
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。
而不同的是,super是告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。
-
利用runtime 底层原理分析
把son.m文件转换成.cpp 文件【终端命令:$clang -rewrite-objc Son.m
】
oc 代码
NSLog(@"%@",NSStringFromClass(self.class));
NSLog(@"%@",NSStringFromClass(super.class));
//新增下面两行代码
[super test];
[self test];
转换成.cpp 文件的代码
NSLog((NSString *)&__NSConstantStringImpl__var_folders_jw_5qlq_4rj54j7dqfnvnfn_lq40000gn_T_Son_08cc44_mi_0,NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_jw_5qlq_4rj54j7dqfnvnfn_lq40000gn_T_Son_08cc44_mi_1,NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"))));
//[super test];
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("test"));
//[self test];
((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("test"));
-
分析
不太熟悉runtime 同学,估计有不太明白,下面我简单的介绍一下
runtime 又一个消息机制,我们一步步来举例分析【Person 为例】 -
1、谈谈objc_msgSend
-
oc 创建一个person对象
Person *p = [Person alloc]; -
变形1
Person *p = objc_msgSend([Person class], @selector(alloc));objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
这是runtime 方法里面的一个函数,表示发送一个消息机制,第 一个参数是消息接收者,第二个参数是调用的具体类方法的 selector】 -
2、谈谈sel_registerName
-
变形2
Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
sel_registerName(const char *str)
向运行时系统注册一个方法名称,并生成SEL和方法名称的映射,最后返回SEL -
3、谈谈class_getSuperclass
class_getSuperclass(Class _Nullable cls)
指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL。
再来研究
[super test];
[self test];
唯一不同的就是:
{(id)self, (id)class_getSuperclass(objc_getClass("Son"))}
这个方法可以看出,调用test 的对象还是 son,只不过用父类指向一个子类对象,去父类方法里面去寻找 test 方法
- 案例【自己去理解】
BOOL result1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [(id)[Son class] isKindOfClass:[Son class]];
BOOL result4 = [(id)[Son class] isMemberOfClass:[Son class]];
NSLog(@"result1 = %d ,result2 = %d,result3 = %d,result4 = %d",result1,result2,result3,result4);
// result1 = 1 ,result2 = 0,result3 = 0,result4 = 0
网友评论