理解“属性”这一概念
-
“属性”(property)是Objective-C的一项特性,用于封装对象中的数据。
-
编译器会把“点语法”转换为对存取方法的调用,使用“点语法”的效果与直接调用存取方法相同。因此使用点语法和直接调用存取方法之间没有丝毫差别。
NSString *lastName = aPerson.lastName; //Same as: NSString *lastName = [aPerson lastName];
-
属性可以拥有的特质分为四类:
- 原子性
- 读/写权限
- 内存管理语义
- 方法名
-
读/写权限
- 具备readwrite(读写)特质的属性拥有“获取方法”(getter)与“设置方法”(setter)。若该属性由@synthesize实现,则编译器会自动生成这两个方法。
- 具备readonly(只读)特质的属性仅拥有获取方法,只有当该属性由@synthesize实现时,编译器才会为其合成获取方法。你可以用此特质把某个属性对外公开为只读属性,然后在“class-continuation分类”中将其重新定义为读写属性。
-
**getter=**指定“获取方法”的方法名。
@property (nonatomic, getter = isOn) Bool on;
在对象内部尽量直接访问实例变量
- 使用“点语法”与不经由存取方法而是直接访问实例变量,两种写法有几个区别:
- 由于不经过Objective-C的“方法派发”(method dispatch)步骤,所以直接访问实例变量的速度当然比较快。在这种情况下,编译器所生成的代码会直接访问保存对象实例变量的那块内存。
- 直接访问实例变量时,不会调用其“设置方法",这就绕过了为相关属性所定义的“内存管理语义”。比方说,如果在ARC下直接访问一个声明为copy的属性,那么并不会拷贝该属性,只会保留新值并释放旧值。
- 如果直接访问实例变量,那么不会触发“键值观测”(Key-Value Observing, KVO)通知。这样做是否会产生问题,还取决于具体的对象行为。
- 通过属性来访问有助于排查与之相关的错误,因为可以给“获取方法"和/或“设置方法”中新增“断点" (breakpoint),监控该属性的调用者及其访问时机。
- 在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应该通过属性来写
- 在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据(因为子类可能会“覆写”设置方法)。
- 有时会使用惰性初始化技术配置某份数据,这种情况下,需要通过属性来读取数据,否则,实例变量就永远不会初始化(因为不走获取方法)。