返回

iOS探索底层-慢速方法查找

IOS

前言

在上一篇文章《iOS探索底层-objc_msgSend&快速方法查找》中,我们探索了objc_msgSend调用过程中的快速查找流程,并分析了其汇编代码。它主要是在cache中快速的查找是否存在方法的实现,如果存在,则直接调用。

慢速方法查找

在快速查找失败的情况下,objc_msgSend将进入慢速查找流程。慢速查找需要遍历类的继承链,逐个类查找方法的实现。这是一个相对耗时的过程,尤其是对于继承链较长的类。

慢速查找过程

慢速查找过程大致可以分为以下几个步骤:

  1. 从接收者对象的类开始,逐个类查找方法的实现。
  2. 如果在某个类中找到了方法的实现,则直接调用该方法。
  3. 如果在所有类中都没有找到方法的实现,则抛出异常。

慢速查找汇编代码

慢速查找的汇编代码如下:

.text
.align 2
_objc_msgSend:
        push    {r0, r1, r2, r3, r12}

        // 检查接收者对象是否为空
        cmp     r0, #0
        beq     L_objc_msgSend_receiver_is_nil

        // 从接收者对象的类开始查找方法的实现
        ldr     r2, [r0, #8]  // 获取接收者对象的类指针

L_objc_msgSend_search_class_loop:
        // 比较类名和方法名是否匹配
        cmp     r1, [r2, #0]  // 比较类名
        bne     L_objc_msgSend_search_class_failed

        cmp     r3, [r2, #4]  // 比较方法名
        bne     L_objc_msgSend_search_class_failed

        // 找到了方法的实现,直接调用该方法
        blx     [r2, #12]  // 调用方法

        // 返回方法调用的结果
        mov     r0, r0
        b       L_objc_msgSend_exit

L_objc_msgSend_search_class_failed:
        // 继续查找下一个类
        ldr     r2, [r2, #16]  // 获取父类指针

        // 如果父类指针为0,则表示没有找到方法的实现
        cmp     r2, #0
        beq     L_objc_msgSend_not_found

        // 跳转到下一个类的查找循环
        b       L_objc_msgSend_search_class_loop

L_objc_msgSend_not_found:
        // 抛出异常
        bl      _objc_msgSend_not_found_exception

L_objc_msgSend_receiver_is_nil:
        // 接收者对象为空,抛出异常
        bl      _objc_msgSend_receiver_is_nil_exception

L_objc_msgSend_exit:
        pop     {r0, r1, r2, r3, r12}

        bx      lr

优化慢速查找性能

为了优化慢速查找性能,我们可以采取以下措施:

  • 减少类的继承深度:类的继承深度越深,慢速查找需要遍历的类就越多,因此减少类的继承深度可以有效提高慢速查找的性能。
  • 避免使用多重继承:多重继承会增加类的继承深度,从而降低慢速查找的性能。因此,应尽量避免使用多重继承。
  • 使用缓存:我们可以使用缓存来存储已经查找过的类和方法的实现。这样,当下次需要查找相同的方法时,我们可以直接从缓存中获取,而无需重新进行慢速查找。

结论

慢速查找是objc_msgSend调用过程中的一个重要组成部分。通过了解慢速查找的过程和汇编代码,我们可以更好地理解objc_msgSend的实现原理。此外,通过采取适当的优化措施,我们可以有效提高慢速查找的性能,从而提高iOS应用程序的性能。