前言
此篇博客需要用到 isa
与 superclass
的指向流程分析,如果你对此还不是很清晰,建议你先通过这篇博客 看透 isa 了解一下 ;如果你已有所掌握,在这里,我们先做一个简短的回顾。
isa
的指向:对象的 isa 指向 类; 类的 isa 指向 元类;元类的 isa 指向 根元类;根元类的 isa 指向 自己。
类的superclass
的指向:类的 superclass 指向 父类, 父类的 superclass 指向 根类 ,根类的superclass 指向 nil;
元类的superclass
的指向:元类的 superclass 指向 父类的元类,父元类的 superclass 指向 根类的元类 根元类的 superclass 指向 根类 根类的 superclass 指向 nil。
示例分析
- 下面的代码输出什么内容?
// Person 继承 NSObject
@implementation Person : NSObject
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[Person class] isKindOfClass:[Person class]];
BOOL re3 = [(id)[NSObject new] isKindOfClass:[NSObject class]];
BOOL re4 = [(id)[Person new] isKindOfClass:[Person class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re6 = [(id)[Person class] isMemberOfClass:[Person class]];
BOOL re7 = [(id)[NSObject new] isMemberOfClass:[NSObject class]];
BOOL re8 = [(id)[Person new] isMemberOfClass:[Person class]];
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
你的答案是什么呢?不妨先停一停,多花些时间思考一下你的答案,然后再继续往下看。
in thinking .......
then
go on
此题主要考察两个方面的内容,① isa
与 superclass
的指向流程;② (+ / -) isKindOfClass
与 (+ / - ) isMemberOfClass
的实现细节。
re1 和 re2 的第一个参数都是 类,所以是对 + (BOOL)isKindOfClass:(Class)cls
方法的考察。
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- 先看 re1
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
传入的cls 为 NSobject, self 指向 NSobject,进入循环
①第一次循环: tcls 为 NSobject meta ,cls 为 NSobject ;执行判断条件
if (tcls == cls)
,不相等;执行tcls = tcls->superclass
,此时 tcls 指向 NSobject meta 的父类 ,即 NSObject。进入第二次循环。②第二次循环:此时 tcls 为 NSobject,cls 依然是 NSobject,执行判断条件
if (tcls == cls)
相等,return YES。所以 re1 的结果为 1。
- re2
BOOL re2 = [(id)[Person class] isKindOfClass:[Person class]];
传入的cls为 NSobject,self指向 Person,进入循环
①第一次循环:tcls 为 Person meta,cls 为 Person类; 执行判断条件
if (tcls == cls)
,不相等,执行tcls = tcls->superclass
,此时 tcls 指向 NSobject metal。进入第二次循环。②第二次循环: tcls 为 NSobject meta ,cls 为 Person类;不相等,执行
tcls = tcls->superclass
,此时 tcls 指向 NSObject。进入第三次循环。③第三次循环: tcls 为 NSobject ,cls 为 Person类;不相等,执行
tcls = tcls->superclass
,此时 tcls 指向 nil。不满足for循环执行条件 tcls。结束循环。所以 re2 的结果为 0。
+ (BOOL)isKindOfClass:(Class)cls
考察的是:判断类或类的父类的类型是否是条件类
re3 和 re4 的第一个参数都是 对象,所以是对 -(BOOL)isKindOfClass:(Class)cls
方法的考察。
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- re3
BOOL re3 = [(id)[NSObject new] isKindOfClass:[NSObject class]];
传入的cls 为 NSObject 类,self 指向 NSObject 的 实例对象
①第一次循环:tcls 指向 NSObject 类,cls 为 NSObject 类,执行判断
if (tcls == cls)
,相等,return YES,结束循环。所以 re3 返回1。
- re4
BOOL re4 = [(id)[Person new] isKindOfClass:[Person class]];
传入的cls 为 Person 类,self 指向 Person 的 实例对象
①第一次循环:tcls 指向 Person 类,cls 为 Person 类,执行判断
if (tcls == cls)
,相等,return YES,结束循环。所以 re4 返回1。
-(BOOL)isKindOfClass:(Class)cls
考察的是 判断对象的类 是否是条件类的子类。
re5 和 re6 的第一个参数都是 类,所以是对 + (BOOL)isMemberOfClass:(Class)cls
方法的考察。
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- 先看 re5
BOOL re5 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
传入的cls 为 NSObject, self 指向 NSObject
self->ISA( ) ,self的 isa 指向 NSObject meta ;NSObject meta 与 NSObject 不相等。
所以 re5 的结果为 0。
- re6
BOOL re6 = [(id)[Person class] isMemberOfClass:[Person class]];
传入的cls 为 Person, self 指向 Person
self->ISA( ) ,self的 isa 指向 Person meta ;Person meta 与 Person 不相等。
所以 re6 的结果为 0。
+ (BOOL)isMemberOfClass:(Class)cls
考察的是类的元类 是否是条件类。
re7 和 re8 的第一个参数都是 对象 所以是对 -(BOOL)isMemberOfClass:(Class)cls
方法的考察。
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- re7
BOOL re7 = [(id)[NSObject new] isMemberOfClass:[NSObject class]];
传入的cls 为 NSObject, self 指向 NSObject 对象
[self class] 为 NSObject 类 ;与 cls 相等。
所以 re7 的结果为 1。
- re8
BOOL re8 = [(id)[Person new] isMemberOfClass:[Person class]];
传入的cls 为 Person, self 指向 Person 对象
[self class] 为 Person 类 ;与 cls 相等。
所以 re8 的结果为 1。
-(BOOL)isMemberOfClass:(Class)cls
考察的是对象 是否是条件类的实例。
- 方法的存储示例
创建 Person类 继承自 NSObject,实现方法如下:
@implementation Person
- (void)sayHello{
NSLog(@"Person say : Hello!!!");
}
+ (void)sayHappy{
NSLog(@"Person say : Happy!!!");
}
@end
分别用class_getInstanceMethod
和 class_getClassMethod
获取 objc_method
下面输出的结果会是什么?
void lgInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
LGLog(@"%s - %p--%p--%p--%p",__func__,method1,method2,method3,method4);
}
在类的结构分析中,我们知道,对象的 实例方法 存储在 类 中,类方法 存储在 元类 之中。
对于method1 :在 Person类 中查找
- (void)sayHello
这样一个实例方法 ,显然是存在的。
对于method2 :在 Person元类 中查找
- (void)sayHello
这样一个实例方法 ,是不存在的。
对于method3 :在 Person类 中查找
+ (void)sayHappy
这样一个实例方法 ,是不存在的。
对于method4 :在 Person元类 中查找
+ (void)sayHappy
这样一个实例方法 ,是存在的。
所以上述结果为:> - 0x1000031b0 -- 0x0 -- 0x0 -- 0x100003148
继续看下面的输出结果:
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p--%p--%p--%p",__func__,method1,method2,method3,method4);
}
我们直接输出结果: > - 0x0 -- 0x0 -- 0x100003148 -- 0x100003148
对于method1 :在 Person类 中查找
- (void)sayHello
这样一个类方法 ,不存在。
对于method2 :在 Person元类 中查找
- (void)sayHello
这样一个类方法 ,不存在。
对于method3 :在 Person类 中查找
+ (void)sayHappy
这样一个类方法 ,存在。
对于method4 :在 Person元类 中查找
+ (void)sayHappy
这样一个类方法 ,存在。
对于method4,为什么 Person元类 中会 + (void)sayHappy
的类方法呢?
我们跟踪到 class_getClassMethod
中
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
由底层实现可见,获取 类方法 就是获取 元类中的 实例方法,这是符合我们预期的。
继续追踪到 cls->getMeta()
方法
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
可见,在获取元类的时候,如果传入的就是元类,那么会返回本身;否则才会继续查找元类,而对于这个例子 Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
传入的已经是 Person 的元类, 那么会直接返回 Person 元类,而不是去找 Person元类的元类 。而 Person 元类中就是存在 + (void)sayHappy
这样一个类方法的,所以 method4 是有返回值的。
为什么这样设计呢?
因为在现实世界中,没人会向元类对象发送消息。
- 下面的代码输出什么内容?
@implementation Son : Father
- (id)init {
self = [super init];
if (self) {
Class son = [self class];
Class Father = [super class];
NSLog(@"%@", NSStringFromClass(Son));
NSLog(@"%@", NSStringFromClass(Father));
}
return self;
}
@end
分析流程:首先我们将 Son.m 编译成 c++ 文件
clang -rewrite-objc Son.m -o Son.cpp
在c++中,看一下是如何实现的。
// @implementation Son
static id _I_Son_init(Son * self, SEL _cmd) {
self = ((Son *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("init"));
if (self) {
Class son = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
Class Father = ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_m__6whbhm2540q9gqrsnmnkmkg40000gn_T_Son_58884b_mi_0, NSStringFromClass(son));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_m__6whbhm2540q9gqrsnmnkmkg40000gn_T_Son_58884b_mi_1, NSStringFromClass(Father));
}
return self;
}
// @end
我们关注这两段代码:
Class son = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
Class Father = ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"));
objc中 super
是编译器标示符,并不像 self
一样是一个对象,遇到向 super
发的方法时会转译成 objc_msgSendSuper(...)
,而参数中的对象还是 self
,于是从父类开始沿继承链寻找 - class
这个方法,最后在NSObject中找到(若无override),此时,[self class]
和 [super class]
已经等价了。
所以 输出的结果 都是 "Son"。