「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。
以前看网上的文章的时候,总感觉理解起来很费劲,蒙圈的感觉,这样看完马上就忘了。
最近复习这方面知识,记忆一下,so这里通过源码来捋一捋下面这个关系图。
个人理解,有误请指正。
这边就不说了。
通过运行时创建类的方法 objc_allocateClassPair 来看看他们的关系。
Class objc_allocateClassPair(Class superclass, const char *name,
size_t extraBytes)
{
Class cls, meta;
// Fail if the class name is in use.
if (look_up_class(name, NO, NO)) return nil;
mutex_locker_t lock(runtimeLock);
// Fail if the class name is in use.
// Fail if the superclass isn't kosher.
if (getClassExceptSomeSwift(name) ||
!verifySuperclass(superclass, true/*rootOK*/))
{
return nil;
}
// Allocate new classes.
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
// fixme mangle the name if it looks swift-y?
objc_initializeClassPair_internal(superclass, name, cls, meta);
return cls;
}
可以看到这个方法里是有一个cls,还有一个meta的,实际是有2个class的,而返回的只有cls.
再往下看objc_initializeClassPair_internal 初始化,我只挑出部分代码来看,完整的可以自己去看源码。
// Connect to superclasses and metaclasses
cls->initClassIsa(meta);
if (superclass) {
meta->initClassIsa(superclass->ISA()->ISA());
cls->superclass = superclass;
meta->superclass = superclass->ISA();
addSubclass(superclass, cls);
addSubclass(superclass->ISA(), meta);
} else {
meta->initClassIsa(meta);
cls->superclass = Nil;
meta->superclass = cls;
addRootClass(cls);
addSubclass(cls, meta);
}
看上面的注释就知道 这里的处理是连接到父类和元类。这里举个例子(修改了一下关系图):
假如创建一个Student类
cls->initClassIsa(meta),这个方法将Student的isa指向StuMeta,Person,NSObject同理 ,如图,与他们的元类之前的虚线正是isa- 判断是否有superclass.
2.1. 如果没有(NSObject):结合源码如图:
ObjcMeta的isa指向了他自己,即(meta->initClassIsa(meta);)
NSObject的父类=Nil,即(cls->superclass = Nil;)
ObjcMeta的父类=NSObject。即(meta->superclass = cls;)。跟源码的逻辑一致
2.2. 如果有父类(以Student为例):
StuMeta指向ObjcMeta(即meta->initClassIsa(superclass->ISA()->ISA());)
Student的父类 =Person,(即cls->superclass = superclass;)
StuMeta的父类=Person的isa,即PerMeta。(meta->superclass = superclass->ISA();) - 而实例对象的isa,从alloc方法里看源码,最后追踪到
_class_createInstanceFromZone这个方法里,里面会分配内存,然后将实例对象的isa指向类。即图中student的isa指向Student
截取部分代码,最终都会调用initIsa。
if (!zone && fast) {
obj->initInstanceIsa(cls, hasCxxDtor);
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
至此通过源码捋完了。
接下来 我们创建一个2个类的文件Person,Student,再来通过clang捋一捋。
用命令clang -rewrite-objc Person.m,clang -rewrite-objc Student.m 转成cpp文件。
打开Person.cpp.翻到最下面 ,你会看到一个初始化函数:
static void OBJC_CLASS_SETUP_$_Person(void ) {
OBJC_METACLASS_$_Person.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_Person.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_Person.cache = &_objc_empty_cache;
OBJC_CLASS_$_Person.isa = &OBJC_METACLASS_$_Person;
OBJC_CLASS_$_Person.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_Person.cache = &_objc_empty_cache;
}
从这里可以捋一下isa和父类的指向关系:(cache先不看)
Person元类的isa指向NSObject的元类
Person元类的父类指向NSObject的元类
Person类的isa指向Person元类
Person类的父类指向NSObject类
与上面源码分析的结果及图中的指向 一致。
再看看Student.cpp
static void OBJC_CLASS_SETUP_$_Student(void ) {
OBJC_METACLASS_$_Student.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_Student.superclass = &OBJC_METACLASS_$_Person;
OBJC_METACLASS_$_Student.cache = &_objc_empty_cache;
OBJC_CLASS_$_Student.isa = &OBJC_METACLASS_$_Student;
OBJC_CLASS_$_Student.superclass = &OBJC_CLASS_$_Person;
OBJC_CLASS_$_Student.cache = &_objc_empty_cache;
}
同样捋一下指向关系:
Student元类的isa指向NSObject元类
Student元类的父类指向Person元类
Student类的isa指向Student元类
Student类的父类指向Person类
与上面源码分析的结果及图中的指向 也是一致的。
最后我们通过实际代码来验证一下这个指向关系。
/// 实例化
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);
撸上以上代码,在最后打上断点,我们来打印一下地址看看是不是如同上面分析的指向。