NSObject的实例对象、类对象、元类之间的关系

1,387 阅读3分钟

如下图所示,是实例对象、类对象、元类之间的关系图,其中实现箭头表示父类关系,虚线表示isa的指向关系(isa可以理解为所属类,下一章介绍)

看到了上图得到的结果,下面介绍探究步骤:

第一步:创建LSPerson类,继承自NSObject,创建LSStudent类,继承自LSPerson

第二部:分别获取NSObject、LSPerson、LSStudent的isa和父类的isa地址,打印他们的地址观察规律,并验证即可

探究过程

先创建LSPerson类,继承自NSObject,创建LSStudent类,继承自LSPerson,然后分别获取他们的isa

LSPerson *per = [LSPerson alloc]; //对象
LSStudent *stu = [LSStudent alloc]; //对象

获取对象的isa

获取对象的isa,以LSPerson的对象per为例,有三种方法

[per class];
[LSPerson class];
object_getClass(per);

然而想获取到元类的isa,只能使用第三种方法,可以参考class类方法和对象方法的源码,如下所示

+ (Class)class {
    return self;
}
- (Class)class {
    return object_getClass(self);
}

由于获取一次之后,就得到了类对象,因此通过class无法获取到元类,只能获取到自己,只能通过object_getClass方法获取

获取父类的Class

同获取isa的过程相同,以LSPerson的对象per为例,也是有三种,均可获取

[per superclass];
[LSPerson superclass];
class_getSuperclass(per);

superclass的源码如下,均为获取本类的父类superclass

+ (Class)superclass {
    return self->superclass;
}
- (Class)superclass {
    return [self class]->superclass;
}
Class class_getSuperclass(Class cls)
{
    if (!cls) return nil;
    return cls->superclass;
}

分别获取LSPerson、LSStudent、NSObject的类、元类、根源类、根源类的isa,以及父类的Class等

先直接上代码

LSPerson *per = [LSPerson alloc]; //对象
LSStudent *stu = [LSStudent alloc]; //对象

Class obj = [NSObject class];//类
Class obj1 = object_getClass(obj);//元类
Class obj2 = object_getClass(obj1);//根源类
Class obj3 = object_getClass(obj2);//根元类的isa
NSLog(@"obj:%p--%p--%p--%p", obj, obj1 , obj2, obj3);

Class per1 = object_getClass(per); //类
Class per2 = object_getClass(per1); //元类
Class per3 = object_getClass(per2); //根元类
Class per4 = object_getClass(per3); //根元类的isa
NSLog(@"per:%p--%p--%p--%p", per1, per2, per3, per4);

Class stu1 = object_getClass(stu); //类
Class stu2 = object_getClass(stu1); //元类
Class stu3 = object_getClass(stu2); //根元类
Class stu4 = object_getClass(stu3); //根元类的类
NSLog(@"stu:%p--%p--%p--%p", stu1, stu2, stu3, stu4);

Class supPer1 = class_getSuperclass([per class]); //父类NSObject
Class supPer2 = class_getSuperclass(supPer1); //NSObject父类nil
Class supPer3 = class_getSuperclass(stu1); //student的元类的父类
Class supPer4 = object_getClass(supPer1); //父类NSObject的元类
Class supPer5 = class_getSuperclass(supPer3); //根源类父类为NSObject类
NSLog(@"supPer:%p--%p--%p--%p--%p", supPer1, supPer2, supPer3, supPer4, supPer5);

打印结果如下所示

obj:0x7fff962b6118--0x7fff962b60f0--0x7fff962b60f0--0x7fff962b60f0
per0x100008490--0x1000084b8--0x7fff962b60f0--0x7fff962b60f0
stu:0x100008508--0x1000084e0--0x7fff962b60f0--0x7fff962b60f0
supPer:0x7fff962b6118--0x0--0x100008490--0x7fff962b60f0--0x7fff962b6118

通过观察结果可以看出

NSObject的类和元类地址不一样,元类的isa和元类地址一致,即元类的isa指向自己,另外,NSObject的元类就是根源类

通过LSPerson、LSStudent案例可以看出,其类的元类地址和NSObject不一致,根源类和NSObject的元类一致

通过super可以可以看出NSObject的父类为nil,类的最终父类是NSObject类,元类的最终父类是根源类,根源类的父类是NSObject

一个类的对象会有多个,其类class只会有一个,其元类metaClass也是只有一个