1、属性——property
Objective-C的属性用于封装对象之中的数据,其作用同类的数据成员类似,但是所起到的作用远远大于普通的数据成员。声明属性使用@property关键字,这样就可以快速方便地为实例变量创建存取器,并可以通过点语法使用使用存取器。获取属性的变量值使用getter方法,设置属性的变量值使用setter方法。
2、property的使用
使用属性的例子如下:
// // Vehicle.h // #import <Foundation/Foundation.h> @interface Vehicle : NSObject @property (nonatomic, copy) NSString *carName; @property (nonatomic, copy) NSString *carType; @end // // Vehicle.m // #import "Vehicle.h" @implementation Vehicle @end // // main.m // #import <Foundation/Foundation.h> #import "Vehicle.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Vehicle *obj1 = [[Vehicle alloc] init]; obj1.carName = @"Ferrari"; obj1.carType = @"SuperSportCar"; NSLog(@"Car name is %@ and type is %@", obj1.carName, obj1.carType); Vehicle *obj2 = [[Vehicle alloc] init]; [obj2 setCarName:@"BMW X5"]; [obj2 setCarType:@"SUV"]; NSLog(@"Car name is %@ and type is %@", obj2.carName, obj2.carType); } return 0; }
@property等同于在头文件中声明了set和get方法,同时也自动在实现文件中使用synthesize实现了set和get方法。相对于自己手动声明数据和方法成员,使用属性可以大幅简化代码。
3、property的特性
在声明属性的时候,还需要制定一些关键字对属性进行修饰,如nonatomatic、copy等。一般用来修饰属性的特性关键字有三类:原子性、存取器控制和内存管理。
(1)、原子性:
- atomic:使用该特性修饰的属性是线程互斥的,即最多只能有一个线程同时访问。该属性是默认的,只有在严格要求线程安全的场合下会使用。
- nonatomic:使用该特性修饰的属性时线程非安全的,可以同时被多个线程访问。使用nonatomic的属性效率相对较高,在大多数场合使用的是这个特性。
(2)、存取器控制:
主要用于控制属性的set和get方法。
- readwrite:默认属性,表示该属性同时支持读操作和写操作,同时具有setter和getter。
- readonly:表示该属性只读,只有getter没有setter。
另外,还可以自定义setter和getter的函数名,如:
@property (nonatoic, setter = mySetter:, getter = myGetter) NSString *name;
(3)、内存管理
内存管理特性表明了该属性与保有它的对象之间的关系:
- assign:默认属性,用于值关系。通常int、float等数值类型极其封装如NSInteger等属性,以及代理对象通常采用assign特性。
- retain:父对象对属性对象拥有所有权,父对象建立后,属性对象的引用计数加1。只要父对象的引用存在,那么属性对象就不会被释放。对于大部分“类”类型的属性,应采用retain特性。
- copy:与retain类似,父对象存在对属性对象的强引用,但是会在父对象建立时为属性对象建立一份拷贝副本,父对象引用的是这一个副本。使用最多的是NSString类型的属性。
在iOS加入了ARC后,属性的内存管理特性新增添了strong和weak两个:
- strong:与retain相同,即父对象对属性对象强引用,属性对象的引用计数+1,属性对象不会在父对象生命周期结束之前被释放。
- weak:类似于assign,即父对象对属性对象弱引用,属性对象的引用计数不增加,父对象也不能干涉属性对象生命周期,当属性对象在其他地方被释放之后,父对象的这个属性被设置为nil。
- unsafe_unretain:该属性类似于assign,说明父对象不对属性对象存在强引用,但是与weak不同的是当属性对象被释放后,父对象的属性不会被设置为nil。
4、直接访问实例变量还是通过属性访问类成员
这两种访问方式有几个区别:
- 直接访问类成员的速度较快,因为省略了Objective-C的“方法派发”,编译出来的代码会直接访问实例成员的内存。
- 直接访问类成员,将绕过其setter和getter方法,那么属性声明时规定的特性将失效。
- 直接访问类成员,不会触及KVO。
在对象外部访问对象的属性成员,总应该使用属性;在对象内部,应该尽量直接访问实例成员。另外,还需要遵循以下规定:
- 对象内部读取数据时直接访问,写入数据时通过属性来写入;
- 在init和dealloc方法中,始终直接访问实例变量;
- 在进行了惰性初始化时,通过属性来读取数据。