runtime 探索.png
这篇文章,我们来看一下在OC中对象和方法,到底是怎么样的。
首先,创建一个非常简单的类,写一个实例方法,然后调用它。我的study
方法写的很简单,打印我的方法名称。
study方法
调用方法
为了看到runtime是怎么调用方法,我们用clang
把main.m
文件编译成C++格式:
clang -rewrite-objc main.m -o main.cpp
编译完成,工程里就多了一个main.cpp
文件,这个文件很长,前面的都是一些准备环境的代码,不用关注,直接拉到文件最后,找到main
函数:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
((void (*)(id, SEL))(void *)objc_msgSend)((id)((NKTest *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NKTest"), sel_registerName("alloc")), sel_registerName("study"));
}
return 0;
}
很明显,OC中调用实例方法实际上就是调用objc_msgSend
,这个函数的两个参数分别是接收消息的对象和消息 SEL
,方法的本质就是发送消息,向NKTest
的实例对象发送一个study
消息。
接下来我们来看NKTest
是什么,在main.cpp
中搜索NKTest
,可以找到:
typedef struct objc_object NKTest;
也就是说我们是OC对象的本质,实际上是一个objc_object
的结构体。在objc
的源码中,也可以看到objc_object
结构体中是我们熟悉的isa
:
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
到这里,我们就基本上看到了对象和方法的本质,那么,我们刚刚说到的向对象发送消息时,传入的是消息的SEL
,SEL
是方法的编号,它只是一个字符串,通过objc_msgSend
这个函数内部处理,用SEL
找到方法的实现指针IMP
,才可以让对象调用它。这是一个很复杂的过程,下一篇文章我们来探索这个过程到底是怎么实现的。
学如不及,犹恐失之。及时学习和整理,是个好习惯哦~下次见啦!