我们都知道对象的本质是一个结构体,那么我今天就来探索一下
一、对象底层编译
先看一段代码:
//直接在main.m写的,方便编译
@interface AAPerson : NSObject
@end
@implementation AAPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
AAPerson *per = [AAPerson alloc];
}
return 0;
}
我们通过clang把它编译成c++文件,来看一下底层编译会变成什么:
//进到文件夹,执行clang命令
clang -rewrite-objc main.m -o main.cpp
看编译后的代码:
#ifndef _REWRITER_typedef_AAPerson
#define _REWRITER_typedef_AAPerson
typedef struct objc_object AAPerson;
typedef struct {} _objc_exc_AAPerson;
#endif
struct AAPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
/* @end */
// @implementation AAPerson
// @end
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
AAPerson *per = ((AAPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AAPerson"), sel_registerName("alloc"));
}
return 0;
}
typedef struct objc_object AAPerson;
AAPerson在底层的确是一个结构体objc_object。
struct NSObject_IMPL NSObject_IVARS;
结构体里放了一个NSObject_IVARS,继承自NSObject_IMPL
NSObject_IMPL也是一个结构体,里面是一个isa
struct NSObject_IMPL {
Class isa;
};
总结:
对象的本质是一个结构体,结构体继承了来自父类的属性,一个isa指针。
二、对象添加属性底层编译
@interface AAPerson : NSObject
@property (nonatomic, copy) NSString *name; //属性
@end
@implementation AAPerson
@end
编译后:
extern "C" unsigned long OBJC_IVAR_$_AAPerson$_name;
struct AAPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_name;
};
编译后,帮我们生产了一个待下划线的_name,并且还有getter方法:
//getter方法
//底层编译会默认传入2个参数:id self, SEL _cmd
static NSString * _I_AAPerson_name(AAPerson * self, SEL _cmd)
{
return (*(NSString **)((char *)self + OBJC_IVAR_$_AAPerson$_name));
}
还有一个setter方法:
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
//setter方法
static void _I_AAPerson_setName_(AAPerson * self, SEL _cmd, NSString *name)
{
objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct AAPerson, _name), (id)name, 0, 1);
}
另外在 method_list 结构体里面:
//_I_AAPerson_name对应 的就是getter方法
/*
"@16@0:8"表示 参数的类型
@ 返回值类型,id类型 16代表这一整段参数所占的长度
@ 参数一类型,id类型 0代表 从0开始,占0~7
: 参数二类型,SEL类型 8代表 从8开始,占8~15
*/
{{(struct objc_selector *)"name", "@16@0:8", (void *)_I_AAPerson_name},
//_I_AAPerson_setName_对应 的就是setter方法
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_AAPerson_setName_},
有个官方的参考表:
总结:
对象的属性,系统会在编译时,帮我们生产_name,getter,setter。
三、对象添加成员变量底层编译
@interface AAPerson : NSObject{
NSString *sex;
}
@end
@implementation AAPerson
@end
编译后:
struct AAPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *sex;
};
编译后,并没有帮我们生产了一个待下划线的_sex,也没有getter方法、也没有setter方法
还有一个细节点:在{ }内声明,一个能够生产实例对象的类,会有一个别称:实例变量。
@interface AAPerson : NSObject{
NSString *name; // 成员变量 : 底层编译不会生成相应的 setter getter
AATeacher *t; // 实例变量 : 是一种特殊的成员变量 (类声明而来 实例 - id (void *))
}
总结:
对象的成员变量,并不会生成 _属性、getter、setter
四、总结
- 对象的本质是结构体
- 对象的属性,会在底层自动生成 _属性、getter、setter
- 对象的成员变量,并不会生成 _属性、getter、setter