对象和方法的本质
对象的本质
Objective-C的对象本质其实是结构体。
我们平时编写的objective-c代码,底层实现其实都是C/C++代码,所以Objective-C的面向对象都是基于C/C++的数据结构实现的,而其中Objective-C的对象和类则主要是基于C/C++的结构体来实现的。
在main函数中定义一个简单对象:
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
}
return 0;
}
可以通过clang -rewrite-objc main.m -o main.cpp命令,将main.m文件进行重写,转换成对应的C/C++代码。
在大约7700多行可以看到这段代码:
struct NSObject_IMPL {
Class isa;
};
struct NSObject_IMPL就是NSObject的底层结构了,所以对象本质其实是结构体。
随便在main函数某处输入Class,点击Jump to Definition,发现如下代码:
typedef struct objc_class *Class;
可以看出Class是结构体objc_class的别名,下面是objc_class源码的其中一部分:
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
...
}
可以看出objc_class继承自结构体objc_object,于是找到objc_object的源码:
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
...
}
objc_object中,第一个私有成员变量isa_t类型的isa,说明所有对象都包含一个类型为isa_t的isa指针。
方法的本质
Objective-C中方法的本质其实是发送消息。
打开main.cpp文件,拉到文件末尾,可以看到:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
}
return 0;
}
可以简单得出,方法的本质是通过objc_msgSend发送消息,其中第一个参数为id消息接受者,第二个参数为sel方法编号。
OC方法函数调用,最终都会通过objc_msgSend进行消息转发,把对应方法编号SEL发送给对应的Class,查找到方法函数实现的指针IMP,找到函数实现的指针IMP就是找到对应的方法实现地址。
通过SEL方法编号查找方法实现指针IMP,苹果提供了两种方案,一种是快速查找,利用缓存机制,使用汇编进行查找,一种是慢速查找,就是利用C、C++递归查找。
因为objc_msgSend要求通过传入一个任意的SEL,最终找到方法实现的IMP指针,而在C语言中,不可能写一个函数去实现保留未知的参数,跳转任意的指针,而汇编语言可以直接通过寄存器操作,比C语言快很多,所以objc_msgSend是用汇编语言编写的。