- OC中的方法的调用,其实都是转换为objc_msgSend函数的调用
- 继续调用进阶回顾二的
SFPerson
对象,我们可以理解为person
的run
方法调用最终在c语言
的如下方法调用:
objc_msgSend(person, @selector(run));
消息接收者(receiver):person
消息名称:run
- objc_msgSend的执行流程:
消息发送 -> 动态解析 -> 消息转发
查看源码
ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame
// 寄存器:消息接受者 receiver
cmp p0, #0 // nil check and tagged pointer check
#if SUPPORT_TAGGED_POINTERS
b.le LNilOrTagged // (MSB tagged pointer looks negative)
#else
b.eq LReturnZero
#endif
ldr p13, [x0] // p13 = isa
GetClassFromIsa_p16 p13 // p16 = class
LGetIsaDone:
CacheLookup NORMAL // calls imp or objc_msgSend_uncached
// 查找缓存
#if SUPPORT_TAGGED_POINTERS
LNilOrTagged:
b.eq LReturnZero // nil check
// tagged
adrp x10, _objc_debug_taggedpointer_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx x11, x0, #60, #4
ldr x16, [x10, x11, LSL #3]
adrp x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
cmp x10, x16
b.ne LGetIsaDone
// ext tagged
adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
ubfx x11, x0, #52, #8
ldr x16, [x10, x11, LSL #3]
b LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif
LReturnZero:
// x0 is already zero
mov x1, #0
movi d0, #0
movi d1, #0
movi d2, #0
movi d3, #0
ret 相当于C语言的return
END_ENTRY _objc_msgSend
- 通过
CacheLookup NORMAL
方法进行缓存中查找,如果没有找到则从STATIC_ENTRY __objc_msgSend_uncached
方法查找MethodTableLookup
查找_class_lookupMethodAndCache3
进行查找,然后查找IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)
有点绕了
3633CBC2E1B7A08BC498A0172CADD441.png
- 查看方法是否在当前类对象的缓存中,如果没有就进行查找调用
Method meth = getMethodNoSuper_nolock(cls, sel);
方法查找
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
runtimeLock.assertLocked();
assert(cls->isRealized());
// fixme nil cls?
// fixme nil sel?
for (auto mlists = cls->data()->methods.beginLists(),
end = cls->data()->methods.endLists();
mlists != end;
++mlists)
{
method_t *m = search_method_list(*mlists, sel);
if (m) return m;
}
return nil;
}
该方法又使用method_t *m = search_method_list(*mlists, sel);
进行查找 发现search_method
static method_t *search_method_list(const method_list_t *mlist, SEL sel)
{
int methodListIsFixedUp = mlist->isFixedUp();
int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {
return findMethodInSortedMethodList(sel, mlist);
} else {
// Linear search of unsorted method list
for (auto& meth : *mlist) {
if (meth.name == sel) return &meth;
}
}
#if DEBUG
// sanity-check negative results
if (mlist->isFixedUp()) {
for (auto& meth : *mlist) {
if (meth.name == sel) {
_objc_fatal("linear search worked when binary search did not");
}
}
}
#endif
return nil;
}
再查找到 sorted方法
static method_t *findMethodInSortedMethodList(SEL key, const method_list_t *list)
{
assert(list);
const method_t * const first = &list->first;
const method_t *base = first;
const method_t *probe;
uintptr_t keyValue = (uintptr_t)key;
uint32_t count;
for (count = list->count; count != 0; count >>= 1) {
probe = base + (count >> 1);
uintptr_t probeValue = (uintptr_t)probe->name;
if (keyValue == probeValue) {
// `probe` is a match.
// Rewind looking for the *first* occurrence of this value.
// This is required for correct category overrides.
while (probe > first && keyValue == (uintptr_t)probe[-1].name) {
probe--;
}
return (method_t *)probe;
}
if (keyValue > probeValue) {
base = probe + 1;
count--;
}
}
return nil;
}
分别使用二分法
和线性查找
进行查找
-
消息转发流程图如下:
228F997CCF8C839E11374E1D38CE0FA9.png
- 总结:首先判断消息接受者
receiver
是否为nil,如果为nil
直接退出,如果不为nil
则从当前接受者类对象receiverClass
的缓存cache
中查找方法,如果查找到就调用,如果没有查找到,去当前接受者类对象的class_rw_t
中查找方法,找到调用,没找到去父类的缓存cache
中查找,如果找到调用,没找到去父类的class_rw_t
中查找方法,找到调用,没找到就行动态方法解析
网友评论