- 可以用@property语法来定义对象中所封装的数据
- 通过“特质”来指定存储数据所需的正确语义
- 在设置属性所对应的实例变量时,一定要遵从改属性所声明的语义。
- 开发iOS程序是应该使用nonatomic属性,因为atomic属性会严重影响性能。
成员变量
@interface EOCPersion: NSObject {
@public
NSString *_firstName;
NSString *_lastName;
@private
NSString *_someInternalData;
}
定义实例变量的作用域。OC中很少这样做。这写法的问题:
对象布局在编译器就固定,碰到实例变量,把实例变量替换为“偏移量”。偏移量为该变量距离存放对象的内存区域的起始地址有多远。
如果重新增加实例变量,会改变内存布局,需要重新编译。 OC解决此问题的方法是:把实例变量单做一种存储偏移量所用的“特殊变量”,交由类对象保管。
属性
属性 = 成员变量 + set方法 + get方法
@interface EOCPerson: NSObject
@property NSString *firstName;
@end
编译器会为属性自动添加成员变量和set方法与get方法。
如果不需要编译器,添加@dynamic
@interface EOCPerson: NSObject
@dynamic firstName, lastName;
@end
属性特质
原子性
编译器默认所合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备nonatomic特质,则不使用同步锁。
@property (nonatomic, copy) NSString *firstName;
读写权限
- readwrite(读写权限),同时获得setter和getter方法。默认
- readonly(只读),只有get方法。
//.h文件
@interface ViewController : UIViewController
@property (nonatomic, strong, readonly) NSString *firstString;
@end
//.m文件
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_firstString = @"内部任意修改";
}
/// 函数返回值置为NO,即不允许直接访问实例变量。禁止KVC来修改
+(BOOL)accessInstanceVariablesDirectly {
return NO;
}
@end
内存管理语义
- assign: 纯量类型(CGFloat、NSInterger等)的简单赋值操作
atomic与nonatomic区别:具备atomic特质的获取方法会通过锁定机制来确保其操作的原子性。如果两个线程读写同一属性,不论何时总能看到有效的属性值。如果不加锁,一个线程更改属性,一个读,会出现线程读到的属性值不对。iOS开发中使用同步锁开销较大,带来性能问题,所以一般不要求属性必须是原子的。不是绝对安全,就算是atomic,也可能会读到不同的属性值。
- strong: 拥有关系。先保留新值,并释放旧值,然后将新值设置上去
- weak:非拥有关系,既不保留新值,也不释放旧值。同assign,属性所指对象遭到摧毁是,属性值会清空
- unsafe_unretained: 同assign,适用对象类型,非拥有关系。属性所指对象遭到摧毁是,属性值不会自动清空
- copy: 拥有关系。设置方法并不保留新值,而是将其拷贝。常用来保护NSString的封装性,因为传递给设置方法的新值可能指向一个NSMutableString类的实例。
方法名
- getter=:指定获取方法的方法名。
@property (nonatomic, getter=isOn) BOOL on;
- setter=:指定设置方法的方法名。