isa 2 个经典问题分析

isa 2 个经典问题分析

一、类的归属问题

1、2 个 API 

objc_getMetaClass() –> 获取元类

class_getMethodImplementation() –> 获取 IMP

2、实例方法 和 类方法 分析

1. 实例方法

class_getInstanceMethod() –> 类的实例方法

2. 类方法

class_getClassMethod() –> class_getInstanceMethod(cls->getMeta(), sel)  

 

从源码可知,获取类方法,即 获取元类的实例方法 <– class_getInstanceMethod(metalCls,sel);

如上 getMeta() 方法,判断如果是元类指直接 return。

之前文章 类的结构分析 中我们已知 isa 走向流程:元类指向根元类,根元类指向自身。

getMeta() 方法当是根元类时,此时便不需要再返回 ISA 了,因为,如果不做限制,那么走到根元类处,将会形成无限递归死循环。这自然是不合理的。而类方法存在元类中,我们已经找到元类处了,也同样不必再向上寻找。

示例代码:

1
2
3
4
5
6
7
int main(int argc, const char * argv[])  {
MYPerson *person = [MYPerson alloc];
Class pClass = object_getClass(person);

myInstanceMethod_classToMetaclass(pClass);// 运行2
// myClassMethod_classToMetaclass(pClass);// 运行1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 获取实例方法
void myInstanceMethod_classToMetaclass(Class pClass){

const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);

Method method1 = class_getInstanceMethod(pClass, @selector(sayInstance));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayInstance));

Method method3 = class_getInstanceMethod(pClass, @selector(sayClass));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayClass));

NSLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

// 获取类方法
void myClassMethod_classToMetaclass(Class pClass){

const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);

Method method1 = class_getClassMethod(pClass, @selector(sayInstance));
Method method2 = class_getClassMethod(metaClass, @selector(sayInstance));

Method method3 = class_getClassMethod(pClass, @selector(sayClass));
// 元类 为什么有 sayClass 类方法
// --> 类方法 ==》元类的实例方法
Method method4 = class_getClassMethod(metaClass, @selector(sayClass));

NSLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

执行结果:

运行 1 结果: - 实例方法

1
2
3
myInstanceMethod_classToMetaclass - 
0x1000031b0-0x0-0x0-0x100003148
// 1 0 0 1 

运行 2 结果: - 类方法

1
2
3
myClassMethod_classToMetaclass-
0x0-0x0-0x100003148-0x100003148
// 0 0 1 1

二、isKindOf & isMemberOfClass

1、isKindOf 源码

+(BOOL)isKindOf() –> 当前类的 isa 元类是否 和 cls 类 相同,一直向上取父类 –> 当前 类的元类 或 元类父类 –> 根元类的父类 NSObject 类

-(BOOL)isKindOf() –> 当前对象的类 是否 和 cls 类 相同,一直向上取父类 –>  当前 实例对象的类 / 父类 –>

2、isMemberOfClass 源码

+(BOOL)isMemberOfClass() –> 当前类的元类

-(BOOL)isMemberOfClass() –> 当前对象的类

3、class 源码

类的 class 是自己;

实例对象的 class 是实例对象的 isa.

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL re3 = [(id)[MyPerson class] isKindOfClass:[MyPerson class]]; //
BOOL re4 = [(id)[MyPerson class] isMemberOfClass:[MyPerson class]]; //
NSLog(@"\n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re7 = [(id)[MyPerson alloc] isKindOfClass:[MyPerson class]]; //
BOOL re8 = [(id)[MyPerson alloc] isMemberOfClass:[MyPerson class]]; //
NSLog(@"\n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
/*
运行结果:
re1 :1
re2 :0
re3 :0
re4 :0
------------------------
re5 :1
re6 :1
re7 :1
re8 :1
*/
}
return 0;
}

运行上面代码,会发现无论是实例还是类方法都没有走进 isKindOfClass 中的断点???LLVM 在编译时做了编译优化。

通过调试可知走到了:objc_opt_isKindOfClass 中:

流程: 顺着继承链向上走 –> superclass

类对象的流程:类对象的 isa –> 元类 –> 根元类 –> NSobject

实例对象流程:实例对象 isa –> 类 –> 父类 –> 父… 类 –> 根类 NSObject

扩展 

object_getClass(id obj) 和 objc_getClass(const char *aClassName) 

object_getClass() –> isa

objc_getClass(“ClassFromStr”)

–> 根据传入的字符,返回类;没有则创建 


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!