为什么要用property属性,理解"属性"的概念.
"属性"(property)是Objective-C的一项特性,用于封装对象中的数据.Objective-C对象通常会把其所需要的数据保存为各种实例变量.实例变量一般通过"存取方法"来访问.getter用于读取变量,setter用于写入变量.
如果用如下方式,声明实例变量,这是Java或C++常用的写法,在这些语言中可以定义实例变量的作用域.
@interface VVPerson : NSObject
@public
NSString *_nickName;
NSString *_age;
@private
NSString *_otherData;
@end
但是上面这种做法在OC却存在问题:对象布局在编译期就已经固定了,只要碰到访问_nickName变量的代码,编译器会替换为"偏移量"(offset),这个偏移量表示:该变量距离存放对象的内存区域的起始地址有多远.但是如果增加一个实例变量,比如:
@interface VVPerson : NSObject
@public
NSDate *_birthDay;
NSString *_nickName;
NSString *_age;
@private
NSString *_otherData;
@end
原来表示 _nickName的偏移量现在指向了 _birthDay.OC对这种问题的解决办法是,把实例变量当做一种存储偏移量所用的"特殊变量",交由"类对象"保管.偏移量会在运行期查找,如果类的定义变了,那么存储的偏移量也就变了,这样无论何时访问实例变量,总能找到正确的偏移量.这就是稳固的"应用程序二进制接口"(Application Binary Interface ,ABI).ABI定义了生成代码时所遵守的规范.有了这种ABI,就可以在实现文件中定义实例变量了.以便保护与类实现有关的内部信息.
这种问题还有一种解决办法,就是不直接访问实例变量,通过个getter和setter.OC语言存取方法有着严格命名规范,所以能根据名称自动创建存取方法.@property语法就是一种标准的写法:编译器会自动写出一套存取方法,用以访问给定类型中具有给定名称的变量.
如果使用了属性,编译器会自动访问属性的方法,此过程叫做"自动合成"(autosynthesis).这个过程由编译器在编译期执行.编译器自动在属性名前加下划线,作为向类中添加的实例变量.
- @synthesize可以用来指定变量的名字.不再使用默认加下划线的名字.
@implementation VVPerson
@synthesize nickName = _nickName;
@synthesize age = _age;
@end
- @dynamic关键字:它会告诉编辑器,不要自动创建实现属性所用的实例变量,也不要为其创建存取方法.如果用代码访问其中的属性,编译器也不会发出警告信息.
@implementation VVPerson
@ dynamic nickName = nickName , age;
@end
属性的四类特质
- 1.原子性
- 2.读写权限
- 3.内存管理语义
- 4.方法名
原子性
atomic(原子性)和nonatomic(非原子性).如果属性具备atomic(原子性),则使用同步锁. nonatomic(非原子性)则相反.iOS开发中都用nonatomic的原因是:在IOS中使用同步锁的开销较大,这会带来性能问题.属性是原子的也并不能保证线程安全,想保证线程安全还需使用更深层的锁定机制.
读写权限
readwrite(读写)特质的属性有getter和setter
readonly(只读)特质的属性仅有getter,只有该属性由@synthesize实现时,编译器才会为其合成获取方法.
内存管理语义
- assign: 简单赋值,不更改索引计数. 只针对纯量类型,如CGFloat或NSInterger;
- strong:strong修饰的属性一般不会自动释放;在OC中,对象默认是强指针,在实际开放中一般属性对象一般用strong来修饰(NSArray,NSDictionary),在使用懒加载定义控件的时候,一般也用strong.
- weak:strong持有对象,而weak不持有对象.当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它。
- copy:建立一个索引计数为1的对象,然后释放旧对象.copy 一般用来修饰 NSString 和 block.
- retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
未完待续