什么是@property

@property可以说是每一个iOS开发者最常用的一句代码,甚至没有之一。但是,在上古的Xcode 4.4时代之前,事情并不是这个样子的。
当时的iOS开发者,每当需要一个属性的时候。总是需要写这么几句话:

.h
@property NSObejct *foo;
.m
@synthesize foo = _foo;

头文件中加上@property,那么编译器会自动添加下面一段代码:

- (NSObject *)foo;
- (void)setFoo:(NSObject *)newFoo;

也就是属性的setter和getter的声明。

那么@synthesize就是对应等效地实现了setter和getter。

- (NSObject *)foo {
return _foo;
}
- (void)setFoo:(NSObject *)newFoo {
_foo = newFoo;
}

而自从Xcode4.5开始,喜大普奔,开发者只需要使用一句

@property NSObject *foo;

就能直接做完三件事:

  1. 生成一个_foo名称的成员变量;
  2. 声明foo属性的setter和getter方法;
  3. 默认实现声明的两个setter和getter方法;

那么在后来的Xcode中,@synthesize还有什么用处呢?

首先我们在一个控制器中,总是需要使用self.view来操作控制器的view属性,而没法用_view成员变量来直接使用。这个就是因为我们默认的成员变量的声明,是在.m中用@synthesize view = _view;这种格式来声明的。那么继承自UIViewcontorller自然是取不到.m中声明的成员变量。于是,我们如果继承了一个父类,在用父类属性的成员变量时,就需要用@synthesize foo = _foo; 来在子类中使用。

然鹅其实还有一个相关的关键字,很少见。它就是@dynamic。

@dynamic 的意思就是跟系统说,不要创建 property 对应的成员变量(就是一般的 _someProperty),也不要自动生成 get/set 方法,同时不要报错,到在运行时我自己会来添加 get/set 方法。比如像 CoreData 的对象,有些属性并不是用 _someProperty 存起来的,而是从数据库里读出来的。那么就不需要系统默认的 getter、setter,而是在运行时生成。


属性

但是我们在开发中,更多所写的,是这个样子

@property (nonatomic, weak) UIView *backgroudView;

那么括号里面的东西,到底又做了什么,一个好的开发者,决不能容忍自己写下的一段代码不知道它的真实作用。
实际上,在括号里的东西,叫做属性的attribute,特征,或者叫特质。一个属性可以拥有的attribute,可以有四种:

原子性

原子性有两个关键字,atomic和nonatomic,很好理解。原子性和非原子性。如果是atomic修饰的属性,那么在默认生成的setter和getter方法中,会通过锁定机制确保属性的atomicity。但是原子性是不能保证线程安全的,这个问题随意搜一下就有答案,不再赘述。那么nonatomic自然就是不加锁的。

读写权限

默认属性会添加readwrite,同时生成setter和getter,所以本质上是由@synthesize来实现的。
而readonly就是代表只生成getter方法,而只能读的属性显然没有意义,所以,readonly属性一般都需要在这个类的实现中直接使用实例变量赋值,或者在class extension中重新定义为读写属性。

指定方法名

这个很简单,就是使用getter=或setter=来指定方法名,用来更改默认的存取成员变量的方法名称,一般只是在BOOL类型属性时常用。

内存管理

这个就是那个经久不衰的问题点。实际上,属性用来封装数据,但是数据本身需要有所有权,所以内存管理的关注点在于持有方式,而不需要关心使用方式。所以,内存管理关键字影响的是setter方法的实现,本质上,是成员变量对赋值的持有方式。
我们暂时只研究ARC下的几个关键字,assign,strong,weak,copy和unsafe_unretained(没错,这个也是ARC支持的修饰)。

  • assign 适用于简单赋值操作,赋值时直接将原值覆盖,没有任何多余操作。
  • strong 实际和strong同门。strong是id类型和对象类型默认的所有权修饰符。所以,strong修饰符显然只能用在id类型和对象类型上。
  • weak 和strong是对应关键字,适用范围同strong一样,作用特征和assign类似,但是个人认为weak才是ARC的精髓所在。稍后展开讨论。
  • copy 这个修饰的结果和strong类似,但是它并不保留新值,而是copy一份,重新保存。这个特质经常用在NSString上保护其封装性。因为mutable类型一旦copy,就保存了当前这一份值储存,成为不可变的类型。
  • unsafe_unretained 这个很少见,因为它的特质同assign相同,但是使用与对象类型。它与weak的区别在于,属性所指的对象清空之后,属性值并不会清空。

先简单认知一下它们的特征,更深入的问题,在之后一篇中详细研究。