《Effective Objective-C 2.0》4、Objective-C类的属性

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。
在对象外部访问对象的属性成员,总应该使用属性;在对象内部,应该尽量直接访问实例成员。另外,还需要遵循以下规定:
  1. 对象内部读取数据时直接访问,写入数据时通过属性来写入;
  2. 在init和dealloc方法中,始终直接访问实例变量;
  3. 在进行了惰性初始化时,通过属性来读取数据。

上一篇:Ubuntu 12.10 (Quantal Quetzal) 启用root登录


下一篇:代码中设置TextView字体加粗