返回
iOS探索底层-慢速方法查找
IOS
2023-09-12 03:45:06
前言
在上一篇文章《iOS探索底层-objc_msgSend&快速方法查找》中,我们探索了objc_msgSend调用过程中的快速查找流程,并分析了其汇编代码。它主要是在cache中快速的查找是否存在方法的实现,如果存在,则直接调用。
慢速方法查找
在快速查找失败的情况下,objc_msgSend将进入慢速查找流程。慢速查找需要遍历类的继承链,逐个类查找方法的实现。这是一个相对耗时的过程,尤其是对于继承链较长的类。
慢速查找过程
慢速查找过程大致可以分为以下几个步骤:
- 从接收者对象的类开始,逐个类查找方法的实现。
- 如果在某个类中找到了方法的实现,则直接调用该方法。
- 如果在所有类中都没有找到方法的实现,则抛出异常。
慢速查找汇编代码
慢速查找的汇编代码如下:
.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应用程序的性能。