@property本质
@property = ivar + getter + setter
属性(property) 有两大概念:ivar(实例变量)、setter/getter(存取方法)
在定义属性后,编译器会自动生成一套存取方法,用以访问给定类型中具有给定名称的变量,所以
@property = getter + setter
@property 自动合成(autosynthesis)
如果使用了属性的话,那么编译器就会自动编写访问属性所需的方法,此过程叫做“自动合成”( auto synthesis),使用时直接通过"self.property"的方式使用。所以一下两组代码是等同的
@interface JWUser : NSObject
@property (nonatomic, readwrite, copy) NSString *name;
@end
@interface JWUser : NSObject
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
自动合成除了生成访问方法外,还会向类中添加适当类型的实例变量,并在属性名前加下划线,以此作为实例变量的名字。
在上例中,会生成一个实例变量,名称为:_name
。我们也可以在.m中通过@synthesize
语法来指定实例变量名字:
@implementation JWUser
@synthesize name = _name;
@end
上述语法将生成的实例变量名字改为:_name
,而不再使用默认的名字。我们可以通过@synthesize
语法将实例变量名称修改成我们想要的,比如
@synthesize name = userName;
但一般不建议这么做,因为不符合默认的书写规范,正常建议还是使用默认命名方案。
自动合成大致的实现原理
OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
setter 与 getter 方法对应的实现函数
ivar_list :成员变量列表
method_list :方法列表
prop_list :属性列表
也就是说我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.
autosynthesize合成实例变量规则:
- 如果指定了成员变量名称(
@synthesize
),会生成一个指定的名称的成员变量;
- 如果这个成员已经存在就不再生成了;
- 如果@synthesize foo;会生产一个名称为foo的成员变量;
- 如果属性名为foo,并且存在名为_foo的成员变量,那么不会合成新的成员变量,参考如下代码;
@property (nonatomic, readwrite, copy) NSArray *array;
@property (nonatomic, readwrite, copy) NSArray *_array;
此时会在 _array处提出警告auto property synthesize will not synthesize property '_object' because it cannot share an ivar with another synthesized property
@property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?
- 原子性 --- nonatomic, atomic
- 读/写权限--- readwrite(读写) readonly(只读)
- 内存--- assign、weak、string、copy、unsafe_unretained
- setter/getter方法名 getter=<函数名> setter=<函数名>
- 其它:nonnull,null_resettable,nullable
- ARC模式下,如果不指定任何关键字,默认关键字包括
基本数据类型
atomic,readwrite,assign
普通Objective-C对象类型
atomic,readwrite,strong