前言
最近在学习OC的过程中被学长问到了有关isKindOfClass 和 isMemberOfClass的区别,在分清这二者的区别前,笔者觉得有必要先了解类、元类、父类的关系。
同时在网上其实已经有了许多有关类、元类、父类的关系的资料,笔者在这里仅仅记录学习的过程。
导入
众所周知我们的isKindOfClass 和 isMemberOfClass既有实例方法,也有类方法,加起来总共四种方法
在这里首先我们要明白OC的底层80%是C语言,平常创建的对象(类也属于对象,类对象)都转换成了底层C语言里面的结构体。
类与对象的源码
我们这里给出类与对象源码的定义:
我们的类的实质上是一个结构体指针:
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
我们再来看看我们对象的定义
我们在我们的类的定义的代码中已经用typedef命名了我们的Class,Class实质上就是一个结构体指针,我们的isa指针指向这个对象所指向的类
我们有关元类的使用应该会在后面学习iOS的消息发送机制时学到,这里到后面会补充。因笔者并未学习过这部分知识,所以这里直接引用学长的定义:
OC的类其实也是一个对象,一个对象就要有一个它属于的类,意味着类也要有一个isa指针,指向其所属的类。那么类的类是什么?就是我们所说的元类(MetaClass),所以,元类就是类的所属类。
相同的,我们的元类也是类,那么应该也有它的所属类,这里就引出一张广为人知的OC图:
这里有几个英文单词我们需要理解一下。
首先是Meta:它的意思就是当前类属于元类
其次是isa:我们在上面提到了,isa实际上是一个指向当前对象所属类的指针
这样我们便可以总结出我们类、元类、父类的基本关系:
isa指向
- 实例对象的所属类实际上就是其所属类,我们的实例对象就是图中的Instance of Subclass。
接下来我们的isa指向了我们的类,那么继续研究我们类的所属类。 - 从图中可以看出,我们类的所属类实际上就指向了我们的元类。
- 接下来我们再看我们的元类,我们所有元类的所属类实际上都是根元类,在笔者参考的资料中是这样理解的,因为我们OC中几乎所有的类都是NSObject的子类,所以我们的根元类也可以认为是我们的NSObject的元类。
- 接着我们再看图中根元类的虚线,根元类所属的类指向了它本身。
superClass指向
我们这里的superClass指向就是我们类的父类,到了这里其实就比较好理解了,元类与我们的类一样,其父类都是一层层往上的,而不像元类所属的类一样,全部指向我们的根元类
在这里唯一需要注意的是我们的根元类的父类是我们的根类,也可以理解为NSObject类。而NSObject类的父类就是nil了。
我们以我们的代码来查看我们所说结论的正确性:
/// 实例化
NSObject *obj = [[NSObject alloc]init];
Person *person = [[Person alloc]init];
Student *student = [[Student alloc]init];
/// 获取实例对象的isa。即类
Class Object = object_getClass(obj);
Class Person = object_getClass(person);
Class Student = object_getClass(student);
/// 通过名字获取类
Class Object1 = objc_getClass("NSObject");
Class Person1 = objc_getClass("Person");
Class Student1 = objc_getClass("Student");
/// 获取类的父类
Class ObjectSup = class_getSuperclass(Object1);
Class PersonSup = class_getSuperclass(Person1);
Class StudentSup = class_getSuperclass(Student1);
/// 获取类的元类
Class ObjectMeta = objc_getMetaClass("NSObject");
Class PersonMeta = objc_getMetaClass("Person");
Class StudentMeta = objc_getMetaClass("Student");
/// 获取元类的父类
Class ObjectMetaSup = class_getSuperclass(ObjectMeta);
Class PersonMetaSup = class_getSuperclass(PersonMeta);
Class StudentMetaSup = class_getSuperclass(StudentMeta);
/// 通过类的isa获取Class ,实际就是元类,所以PersonMeta1的地址和PersonMeta是一样的,StudentMeta1的地址和StudentMeta是一样的。
Class ObjectMeta1 = object_getClass(Object1);
Class PersonMeta1 = object_getClass(Person1);
Class StudentMeta1 = object_getClass(Student1);
/// 通过元类的isa获取Class, 实际都是根元类,所以PersonMetaIsa和StudentMetaIsa,ObjectMetaIsa的地址是一样的
Class ObjectMetaIsa = object_getClass(ObjectMeta);
Class PersonMetaIsa = object_getClass(PersonMeta);
Class StudentMetaIsa = object_getClass(StudentMeta);
加上断点后编译结果:
本篇文章参考的资料:
iOS 通俗的理解类,父类,元类的关系
[iOS开发]类,父类,元类的关系总结