對于oc的方法查找大家比較熟悉了,所有的方法調(diào)用都會走objc_msgSend
該api必須兩個參數(shù),receiver和SEL,receiver就是該對象的isa指針,然后先在cache里面查找,如果沒找到再去methodLists里面查找,如果還沒有就去superclass里面找進(jìn)行遞歸操作,都找不到就會進(jìn)行消息轉(zhuǎn)發(fā)操作
下面是老版的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,它分為三種派發(fā)方式:靜態(tài)派發(fā),動態(tài)派發(fā)和消息派發(fā)(就是oc里面的派發(fā)方式)
靜態(tài)派發(fā)是最快的.我理解就是在編譯的時候已經(jīng)確定了函數(shù)地址進(jìn)行直接調(diào)用,具體api如:static 修飾func,extension包含的func
動態(tài)派發(fā):他引入了v-table表的概念,從swift源碼看v-table表在編譯的時候回存儲在metal對象里面,調(diào)用查找方式類似消息發(fā)送查找,不同的是他的查找相對淳樸,直接采用指針偏移點方式查找,由于編譯時已經(jīng)確定v-table表,不需要消息發(fā)送那么復(fù)雜的緩存查找方式
可以通過SIL命令來查看當(dāng)前類的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());
// 根據(jù)方法描述取得該方法在vtable中的地址偏移
auto vtableOffset = vtable->getVTableOffset(description) + index;
// 本身類的起始地址
auto *words = reinterpret_cast<void * const *>(metadata);
// 得到動態(tài)方法的當(dāng)前實際地址
return *(words + vtableOffset);
}
參考
http://www.itdecent.cn/p/985bef8dfd30
http://www.itdecent.cn/p/ea01fe230b03
http://www.itdecent.cn/p/a4ca25caa6c9