Fork me on GitHub

iOS入门——@property属性

入门

@property属性详解
属性大概分为三个方面:原子性、存取、内存管理:

  1. nonatomic / atomic
  2. readonly / readwrite
  3. retain / copy / strong / weak /assign

我的理解:property属性的核心主要是实现变量的getter和setter方法(然后就可以通过点语法获取变量),在此之上,附加的关键字不同,预编译的实现也有区别,所以功能也不同。

这里概括下:@property 声明属性其实是做了三件事:

  • .h:声明了getter和setter方法;
  • .h:声明了实例变量(默认:下划线+属性名);
  • .m:实现了getter和setter方法。

一、 首先是线程安全:

atomic(系统默认),在多线程环境下,利用aotmic保证线程安全。内部主要是通过自旋锁实现,而且保证的也是读写操作的原子性,并没有实际上我们想要的线程安全(比如自加这种额外操作)。所以一般线程安全还需要我们在外部自己实现。

nonatomic 跟atomic相反,可以被多个线程同时访问,效率较高但是安全性较低。

二、存取方法:

readwrite(系统默认):可读可写,表明该属性同时拥有setter和getter方法。

readonly:只读属性,只有getter方法,不希望属性在类外被改变。一般在.h文件中常用。

@synthesize:编译器在.m中自动合成getter和setter的实现(主要由编译器在编译期执行),但是这个在xcode4.5以后就不需要了,一个property就能搞定。

@dynamic:属性的getter和setter方法由用户自己实现,编译器不自动生成。这个时候还需要我们显示的声明下属性。

三、内存管理:

copy:内容拷贝。copy属性会在赋值前,复制一个对象,这个copy修饰的属性(变量)会指向一个新对象,所以原对象的改变就不会影响新值的变化。使用:防止属性被意外修改。所有mutable(可变)的属性类型,如NSString, NSArray, NSDictionary等等(对应可变的类型:NSMutableString, NSMutableArray,NSMutableDictionary)这些非可变类型在属性赋值时,右边的值有可能是它们的可变版本。这样就会出现属性值被意外改变的可能。所以它们都应该用copy。

1
2
3
4
//应用copy属性:
- (void)setNameCopy:(NSString *)nameCopy {
_nameCopy = [nameCopy copy];
}

注: 所以如果用copy修饰NSMutableString、NSMutableArray会出错,因为在set的时候,会将原本mutable的对象,copy成了immutable的对象。

strong(ARC中默认):强引用,表示实例变量对传入的对象要有所有权关系。使用:对象类型,比如自定义对象,控制器对象。

weak:弱引用,在setter方法中,对传入的对象不进行引用计数加1的操作,当该对象引用计数为0时,即该对象被释放后,用weak声明的实例变量指向nil。使用:代理对象(在delegate patterns中常用weak解决strong reference cycles(以前叫retain cycles)问题),IBOutlet。

assign:非ARC时代的特性,作用和weak类似:简单赋值,不改变引用计数,但是不同的是如果对象被销毁,指向该对象的assign属性并不会设置为nil,这时候再访问这些属性就会crash。在ARC下,assign适用于基本数据类型(默认)。使用:int、float、double、BOOL、NSInteger等。
retain:指针拷贝,非ARC的特性,现在在ARC中已经不怎么使用了。与strong功能一致。

四、其他:

getter= 和 setter= :重命名getter和setter方法,在ARC中存取方法不能以new开头,所以不能以new开头命名一个属性,比如:

1
@property (copy, nonatomic) NSString *newName;

这样就会报错,解决办法:

1
@property (copy, nonatomic, getter=theNewName) NSString *newName;

Nullability

  • nullable:对象可为空
  • nonnull:对象不可为空
  • null_unspecified:未指定(默认)
  • null_resettable:调用set方法去set属性时,可以传入nil,但是get返回值时,不会为空。所以保证即使传入nil,也会返回一个非空的值。所以一般设置为null_resettable时,需要我们去重写getter或者setter方法,保证返回值不为空。

总结、

  • 在iOS开发上,大部分情况下主要都是nonatomic;
  • 对外「只读」的,写上readonly
  • 一般的对象属性,写上strong(用retain也可以,比较少用),也可以不写,ARC下对象类型默认为strong,需要解决strong reference cycles问题的对象属性,strong改为weak
  • 有mutable(可变)版本的对象属性,strong改为copy
  • 基本数据类型(int, float, BOOL)(非对象属性),用assign