iOS 类的加载原理(二)
2024-01-16 15:57:33
深入解析 iOS 类的加载原理:realizeClass 方法和类地址
realizeClass 方法:类的实现
在 iOS 类的加载原理(一) 中,我们探索了 readClass 方法,它将类名称与地址联系起来。然而,类的加载过程远不止于此。现在,让我们深入了解另一个关键方法:realizeClass。
realizeClass 方法是类加载过程中的关键步骤。它的作用是将类的代码段加载到内存中,并解析方法实现的代码段。realizeClass 方法位于 Objective-C 运行时库中。它首先检查类是否已经加载。如果没有,它会调用 readClass 方法加载类的元数据。
下面是 realizeClass 方法的实现:
BOOL realizeClass(Class cls) {
if (cls->isa != cls) {
return NO;
}
if (cls->cache & CLS_REALIZED) {
return YES;
}
cls->cache |= CLS_REALIZED;
BOOL result = objc_loadObjCMethodList(cls);
if (!result) {
cls->cache &= ~CLS_REALIZED;
return NO;
}
return YES;
}
让我们逐行分析一下这段代码:
- 它首先检查类的 isa 指针是否指向它本身。如果不是,则表示该类尚未加载,需要调用 readClass 方法加载类的元数据。
- 接下来,它检查类的 cache 属性是否包含 CLS_REALIZED 标志。如果包含,则表示该类已经加载,直接返回 YES。
- 如果没有 CLS_REALIZED 标志,则表示该类尚未加载,需要调用 objc_loadObjCMethodList 方法加载类的代码段。objc_loadObjCMethodList 方法负责解析方法实现的代码段,并将其加载到内存中。如果加载成功,则将 CLS_REALIZED 标志添加到类的 cache 属性中,并返回 YES。否则,将 CLS_REALIZED 标志从类的 cache 属性中删除,并返回 NO。
类地址与类名称
在类加载过程中,类地址起着至关重要的作用。类地址是一个唯一的标识符,用于区分不同的类。类地址与类名称相关联,可以通过类名称来查找类的地址。
在 Objective-C 中,类的地址存储在类的元数据结构中。类的元数据结构是一个包含有关类信息的数据结构,其中包括类的名称、类的父类、类的实例大小、类的属性和方法等信息。
类的地址可以通过 objc_getClass 方法获取。objc_getClass 方法接收一个类名作为参数,并返回该类的地址。例如,以下代码获取 NSString 类的地址:
Class NSStringClass = objc_getClass("NSString");
类的地址也可以通过 objc_lookUpClass 方法获取。objc_lookUpClass 方法接收一个类名作为参数,并返回该类的地址。与 objc_getClass 方法不同的是,objc_lookUpClass 方法会先检查类是否已经加载,如果没有,则会调用 readClass 方法加载类的元数据。例如,以下代码获取 NSString 类的地址:
Class NSStringClass = objc_lookUpClass("NSString");
总结
在本博客中,我们深入探讨了 iOS 类的加载原理。重点关注 realizeClass 方法在类加载过程中的作用,以及它是如何解析方法实现的代码段来实现类的初始化的。我们还探讨了类地址在类加载过程中的重要性,以及它是如何与类名称相关联的。
常见问题解答
- realizeClass 方法什么时候被调用?
realizeClass 方法在类第一次被使用时被调用。 - realizeClass 方法解析了哪些内容?
realizeClass 方法解析了方法实现的代码段。 - 类地址如何与类名称相关联?
类地址存储在类的元数据结构中,类名称也是元数据的一部分。 - objc_getClass 方法和 objc_lookUpClass 方法有什么区别?
objc_getClass 方法只返回已加载类的地址,而 objc_lookUpClass 方法会先检查类是否已加载,如果没有,则会调用 readClass 方法加载类的元数据。 - realizeClass 方法是否会在多线程环境中引发竞争条件?
不会,因为类加载是线程安全的。