返回

iOS runtime 深入浅出之三,objc_msgSend 拾遗杂谈 (7)

IOS

前言

在上一篇文章中,我们探讨了 iOS 底层原理 runtime-object_class 拾遗基础,了解了 arm64 之后 isa 是如何使用联合体存储更多的数据,以及如何自定义和使用联合体。我们还讨论了 objc_class->cache_t cache 是一个缓存最近调用 class 的方法,当缓存剩余空间小于 16 个时,系统就会将其中一些方法从缓存中移除。

在这篇文章中,我们将继续深入探究 iOS runtime,重点关注 objc_msgSend 的工作原理,并探讨如何使用自定义联合体和 objc_class->cache_t cache 来优化应用程序的性能。

objc_msgSend 的工作原理

objc_msgSend 是 Objective-C 中用于发送消息的方法,它在运行时动态解析消息并调用相应的方法。objc_msgSend 的工作原理可以分为以下几个步骤:

  1. 查找接收者对象的类。
  2. 在接收者对象的类中查找消息选择器对应的方法。
  3. 检查方法的访问权限并确保调用者有权访问该方法。
  4. 为方法的参数分配内存。
  5. 将参数压入栈中。
  6. 将接收者对象压入栈中。
  7. 调用方法。
  8. 将方法的返回值压入栈中。
  9. 从栈中弹出参数和接收者对象。
  10. 返回方法的返回值。

自定义联合体和 objc_class->cache_t cache 的使用

正如我们在上一篇文章中提到的,我们可以通过自定义联合体来扩展 objc_class 结构体,从而存储更多的数据。例如,我们可以定义一个名为 MyClass 的类,并使用一个名为 myData 的联合体来存储一些自定义数据:

@interface MyClass : NSObject {
    union {
        Class isa;
        struct {
            unsigned int reserved : 16;
            unsigned int bits : 16;
        } bits;
    } _myData;
}

@property (nonatomic, assign) NSUInteger myData;

@end

在上面的代码中,_myData 联合体包含两个成员:isabitsisa 成员指向类的 isa 指针,而 bits 成员是一个包含两个 16 位整数的结构体。我们可以使用 myData 属性来访问和修改联合体中的数据。

我们还可以使用 objc_class->cache_t cache 来缓存最近调用 class 的方法。这可以提高方法调用的性能,因为系统不需要每次都搜索类的方法列表。我们可以使用以下代码来访问和修改 cache:

objc_class->cache_t *cache = objc_getClassCache();

cache 指针指向一个包含多个缓存行的数组,每个缓存行包含一个方法选择器和一个指向方法的指针。我们可以使用以下代码来向缓存中添加一个方法:

objc_setMethodInCache(cache, selector, method);

selector 参数是方法选择器,method 参数是指向方法的指针。

性能优化

我们可以通过自定义联合体和 objc_class->cache_t cache 来优化应用程序的性能。例如,我们可以使用联合体来存储一些经常访问的数据,这样就可以避免多次调用 getter 和 setter 方法。我们还可以使用 cache 来缓存最近调用 class 的方法,这样就可以提高方法调用的性能。

总结

在本文中,我们深入探讨了 iOS runtime 中的 objc_msgSend 的工作原理,并了解了如何使用自定义联合体和 objc_class->cache_t cache 来优化应用程序的性能。这些知识可以帮助我们编写出更高效、更健壮的应用程序。