前面我们分析了对象的创建过程,那么对象的本质是什么呢?我们知道,OC 是通过 LLVM
编译的,而 clang
是 LLVM
的编译前端,我们可以通过 clang
来一探究竟。
clang 编译源文件
我们从简单的 mian.m
文件开始:
@interface SMBook : NSObject { |
然后用 clang
命令:
clang -rewrite-objc main.m -o main.cpp |
得到 main.cpp
文件。文件很长,因为包括编译链接的文件等。
编译后文件解析
我们打开 main.cpp
文件,直接滑到最底端,能看到我们的 SMBook
:
.... |
对象构造函数
老套路,我们通过搜索查找我们的 OBJC_CLASS_SETUP_$_SMBook
:
static void OBJC_CLASS_SETUP_$_SMBook(void ) { |
这是一个构造函数:
- 元类相关的
isa
、superclass
、cache
- 类相关的
isa
、superclass
、cache
类的 isa
指向 OBJC_METACLASS_$_SMBook
:
extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_SMBook __attribute__ ((used, section ("__DATA,__objc_data"))) = { |
注意这里的类型 _class_t
:
struct _class_t { |
这就是后面我们要继续探索的类的结构了。
其实还有别的如:_category_t
、_protocol_t
等。
回到我们今天的正题:对象的结构。
对象结构体
我们继续搜索 SMBook
:
|
NSObject_IVARS
继承自NSObject
的属性:
typedef struct objc_object NSObject;
typedef struct {} _objc_exc_NSObject;
struct NSObject_IMPL {
Class isa;
};对象自己的属性:
属性的
getter
方法:static NSString * _I_SMBook_name(SMBook * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_SMBook$_name)); }
属性的
setter
方法:static void _I_SMBook_setName_(SMBook * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SMBook, _name), (id)name, 0, 1); }
从上面两个方法中观察到两个参数:
self
_cmd
实例方法:
static void _I_SMBook_sayHello(SMBook * self, SEL _cmd) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_yb_37j_8lyx0g1_dtywfftgmc880000gn_T_main_7812b7_mi_0);
}类方法:
static void _C_SMBook_sell(Class self, SEL _cmd) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_yb_37j_8lyx0g1_dtywfftgmc880000gn_T_main_7812b7_mi_1);
}
这就是我们在开发过程中两个隐藏参数,在方法调用的过程中个,这两个参数不需要用户传递。
对象实现
我们继续往下看:
变量列表
static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t),
2,
{{(unsigned long int *)&OBJC_IVAR_$_SMBook$_author, "_author", "@\"NSString\"", 3, 8},
{(unsigned long int *)&OBJC_IVAR_$_SMBook$_name, "_name", "@\"NSString\"", 3, 8}}
};这里有两个变量:
_author
_name
实例方法列表:
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[3];
} _OBJC_$_INSTANCE_METHODS_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
3,
{{(struct objc_selector *)"sayHello", "v16@0:8", (void *)_I_SMBook_sayHello},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_SMBook_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_SMBook_setName_}}
};三个实例方法:
- sayHello
- 属性方法:
name
setName
类方法列表:
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_$_CLASS_METHODS_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"sell", "v16@0:8", (void *)_C_SMBook_sell}}
};类方法:
sell
属性列表:
static struct /*_prop_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count_of_properties;
struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_prop_t),
1,
{{"name","T@\"NSString\",C,N,V_name"}}
};属性:
+ name
元类的 ro
static struct _class_ro_t _OBJC_METACLASS_RO_$_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
1, sizeof(struct _class_t), sizeof(struct _class_t),
(unsigned int)0,
0,
"SMBook",
(const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_SMBook,
0,
0,
0,
0,
};类的 ro
static struct _class_ro_t _OBJC_CLASS_RO_$_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
0, __OFFSETOFIVAR__(struct SMBook, _author), sizeof(struct SMBook_IMPL),
(unsigned int)0,
0,
"SMBook",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_SMBook,
0,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_SMBook,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_SMBook,
};
从这几个里面发现:
- 对象的成员变量会进变量列表
- 对象的属性会进变量列表和属性列表,同时创建
getter
和setter
方法 - 实例方法进实例方法列表
- 变量列表、属性列表和方法列表都会放到类的
ro
- 类方法进类方法列表
- 类方法列表放在元类的
ro
对象的本质
clang 的两条命令:
普通的
.m
文件:clang -rewrite-objc main.m -o main.cpp
当文件内引用了动态库如
UIKit
的.m
文件:clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m
实例创建与方法调用
int main(int argc, const char * argv[]) { |
方法的调用通过 objc_msgSend
实现。