Effective Objective-C 2.0 第6条:理解“属性”

来源:互联网 发布:java获取文件夹的路径 编辑:程序博客网 时间:2024/05/25 01:35

用OC等面向对象语言编程时,“对象”就是“基本构造单元”,在对象之间传递数据并执行任务的过程就叫做“消息传递”。需要熟悉这两个特性的工作原理。

属性

实例变量存取

实例变量一般通过“存取方法”来访问,其中“获取方法”(getter)用于读取变量值,“设置方法”(setter)用于写入变量值。是OC 2.0里的“属性”概念。
点语法是为了调用属性。

@interface EOCPerson : NSObject {@public    NSString* _firstName;    NSString* _lastName;@private    NSString* _someInternalData;}

问题:对于OC而言,对象布局在编译器就已经很稳固了,只要碰到访问_firstName变量的代码,编译器就把其替换为“偏移量”,这个偏移量就是硬编码,表示该变量距离存放对象的内存区域的起始地址有多远。若又加了一个实例变量,那就麻烦了。

@interface EOCPerson :NSObject {@public    NSDate* _dateOfBirth;    ...}

原来指向_firstName的偏移量现在却指向了_dateOfBirth。运行期出现不一致的现象。
OC对于处理此种问题,做法是吧实例变量当做一种存储偏移量所用的“特殊变量”,交由“类对象”保管。偏移量会在运行期查找,如果类的定义变了,那么存储的偏移量也变化了,无论何时访问实例变量,总能访问到正确的偏移量。这就是稳固的“应用程序二进制接口”(ABI)。

属性存取

@interface EOCPerson : NSObject@property NSString* firstName;@property NSString* lastName;@end

如果要访问属性,可以使用点语法
例如

self.firstName 点语法调用属性
_firstName 直接调用实例变量(类内部)

属性有很多优势,如果使用了属性的话,那么编译器就会自动编写访问这些属性所需的方法,此过程叫做“自动合成”。除了生成方法代码外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前加下划线(_XX),以此作为实例变量的名字。也可以在实现文件里通过@synthesize语法来制定实例变量:

@implementation EOCPerson@synthesize firstName = _firstName;@synthesize lastName = _lastName;@end

如果阻止编译器自动合成存取方法,就是使用@dynamic关键字。

@implementation EOCPerson@dynamic firstName, lastName;@end

属性特质(attribute)

注意:若是自己定义存取方法,那么就应该遵从与属性特质相符的语义

  • 原子性

原子性:atomic(编译器所生成的方法会通过锁定机制确保其原子性)
非原子性:nonatomic

开发iOS程序,所有的属性都声明为nonatomic,原因:iOS使用同步锁的开销比较大,这会带来性能问题,一般情况下并不要属性必须是“原子的”,因为这并不能保证“线程安全”,如果实现“线程安全”的操作,还需采用更为深层的锁定机制才可以。

  • 读/写权限

readwrite:获取方法 与 设置方法
readonly:获取方法

  • 内存管理语义

assign:针对“纯量类型(scalar type)”(例如NSInteger,BOOL)的简单复制操作。

strong:针对“拥有关系(owning relationship),为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后将新值复制上去。

weak:针对“非拥有关系”(nonowning relationship),为这种属性设置新值时,设置方法既不保留新值,也不释放旧值,不同于assign的是当属性所指的对象遭到摧毁时,属性值也会被清空(nil)。

unsafe_unretained:语义同assign,但是它适用于对象类型,针对“非拥有关系(unretained)”,当目标遭到摧毁时,属性值不会自动清空。

copy:设置方法并不保留新值,而是将其“copy”。多用于NSString类型。

  • 方法名

getter=:指定 获取方法 的方法名。
setter=:制定 设置方法 的方法名。

如果要再设置属性所对应的实例变量时,一定要遵循该属性所声明的语义

0 0
原创粉丝点击