swift与oc方法查找比较
2021-10-01 本文已影响0人
不拘小节123456
对于oc的方法查找大家比较熟悉了,所有的方法调用都会走objc_msgSend
该api必须两个参数,receiver和SEL,receiver就是该对象的isa指针,然后先在cache里面查找,如果没找到再去methodLists里面查找,如果还没有就去superclass里面找进行递归操作,都找不到就会进行消息转发操作
下面是老版的runtime,但是逻辑类似,好理解
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
}
// 方法的定义
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
对于swift,它分为三种派发方式:静态派发,动态派发和消息派发(就是oc里面的派发方式)
静态派发是最快的.我理解就是在编译的时候已经确定了函数地址进行直接调用,具体api如:static 修饰func,extension包含的func
动态派发:他引入了v-table表的概念,从swift源码看v-table表在编译的时候回存储在metal对象里面,调用查找方式类似消息发送查找,不同的是他的查找相对淳朴,直接采用指针偏移点方式查找,由于编译时已经确定v-table表,不需要消息发送那么复杂的缓存查找方式
可以通过SIL命令来查看当前类的v-table表
swiftc -emit-sil main.swift
void *
swift::swift_lookUpClassMethod(const ClassMetadata *metadata,
const MethodDescriptor *method,
const ClassDescriptor *description) {
assert(metadata->isTypeMetadata());
assert(isAncestorOf(metadata, description));
auto *vtable = description->getVTableDescriptor();
assert(vtable != nullptr);
auto methods = description->getMethodDescriptors();
unsigned index = method - methods.data();
assert(index < methods.size());
// 根据方法描述取得该方法在vtable中的地址偏移
auto vtableOffset = vtable->getVTableOffset(description) + index;
// 本身类的起始地址
auto *words = reinterpret_cast<void * const *>(metadata);
// 得到动态方法的当前实际地址
return *(words + vtableOffset);
}
参考
https://www.jianshu.com/p/985bef8dfd30
https://www.jianshu.com/p/ea01fe230b03
https://www.jianshu.com/p/a4ca25caa6c9