@property = ivar + getter + setter
翻译出来就是:
属性(property)等于实例变量(ivar)加上存取方法(getter和setter,实例变量用于存储数据,而存取方法用来读取写入该实例变量的数据有swift开发经验的人对这个感触应该表较深(存储属性和计算属性)
编译器会自动为@property添加实例变量和存取方法,当你重写一个存取方法的时候不用手动写实例变量:@synthesize name = _name;
,但是当你重写setter和getter方法时,你需要添加这行代码才能通过编译。
property在runtime中是objc_property_t定义如下:
typedef struct objc_property *objc_property_t;
而objc_property是一个结构体,包括name和attributes,定义如下:
struct property_t {
const char *name;
const char *attributes;
};
而attributes本质是objc_property_attribute_t,定义了property的一些属性,定义如下:
/// Defines a property attribute
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
而attributes的具体内容是什么呢?其实,包括:类型,原子性,内存语义和对应的实例变量。
例如:我们定义一个string的property@property (nonatomic, copy) NSString *string;
,通过 property_getAttributes(property)
获取到attributes并打印出来之后的结果为T@“NSString”,C,N,V_string
其中T就代表类型,可参阅Type Encodings,C就代表Copy,N代表nonatomic,V就代表对于的实例变量。
Code | Meaning |
---|---|
c | A char |
i | An int |
s | A short |
l | A long l is treated as a 32-bit quantity on 64-bit programs. |
q | A long long |
C | An unsigned char |
I | An unsigned int |
S | An unsigned short |
L | An unsigned long |
Q | An unsigned long long |
f | A float |
d | A double |
B | A C++ bool or a C99 _Bool |
v | A void |
* | A character string (char *) |
@ | An object (whether statically typed or typed id) |
# | A class object (Class) |
: | A method selector (SEL) |
[array type] | An array |
{name=type…} | A structure |
(name=type…) | A union |
bnum | A bit field of num bits |
^type | A pointer to type |
? | An unknown type (among other things, this code is used for function pointers) |
“自动合成”( autosynthesis)
完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译 器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。在前例中,会生成两个实例变量,其名称分别为 _firstName 与 _lastName。也可以在类的实现代码里通过 @synthesize 语法来指定实例变量的名字.
@implementation Person
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
反编译相关的代码,他大致生成了五个东西
OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
setter 与 getter 方法对应的实现函数
ivar_list :成员变量列表
method_list :方法列表
prop_list :属性列表
也就是说我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.