OC中的属性property按照其功能分为以下三种类型:
- 线程安全
- 内存管理
- 读写权限
缺省情况下,基本数据类型的修饰词是:atomic、assign、readwrite;普通对象的修饰词是:atomic、strong、readwrite
线程安全:atomic与nonatomic
atomic:原子属性;修饰的对象会保证 setter 和 getter 方法的完整性,任何线程访问时得到的是一个完整的初始化后的对象。由于需要保证这种操作的完成,所以速度比较慢。atomic比nonatomic安全,但也不是绝对的线程安全,如果多个线程同时调用 setter 和 getter 方法时,就会导致获得的对象值不一样,如果要保证绝对的线程安全,可通过加锁的方式,例如@synchronized.
nonatomic:非原子属性;修饰的对象无法保证 setter 和 getter 方法的完整性,一旦有多个线程访问时,可能会返回没有初始化的对象,因此 nonatomic 比 atomic 速度快,也不是线程安全的。
因此atomic相比于nonatomic来说,依然不能保证绝对的线程安全,性能速度甚至比nonatomic差很多,所以一般都用nonatomic。
内存管理:strong、copy、weak、assign
strong:指向并且拥有该对象。修饰的对象引用计数加1。
copy:类似于strong,区别在于strong是多个指针指向同一个地址;copy是每次在内存中复制一份对象,指针指向不同的地址。
copy涉及到深拷贝、浅拷贝以及不完全深拷贝(copy以及mutableCopy的拷贝后面单独讲)。
- 深拷贝:内容拷贝,重新开启一块内存
- 浅拷贝:指针拷贝,对象的引用计数加1
- 不完全深拷贝:常见于修饰集合类对象,对于集合本身是深拷贝,即重新开辟一块内存,不影响被修饰集合对象的引用计数,但是对于集合内部的元素是浅拷贝,即集合内部元素对象的引用计数加1
weak:指向但不拥有该对象;用于修饰OC中的对象,其修饰的对象引用计数不加1,不影响被修饰对象的生命周期,在被修饰对象释放销毁时,无需手动设置,weak属性指针自动置为nil ,该对象会自行在内存中被销毁。在OC中,对nil调用方法或发送消息,不会引起奔溃。
- weak使用场景:代理属性用weak修饰,防止循环引用,对象无法释放而引起内存泄漏。
assign:主要用于修饰基本数据类型,这些数值主要存在栈区;assign可以用来修饰对象,和weak一样,其修饰的对象引用计数不加1 ,区别在于被修饰对象释放销毁时,assign属性指针不会置为nil,但是此指针指向的内存区域已经销毁,调用方法或发送消息会引发“野指针”错误奔溃。
strong、copy、weak只能用于修饰对象,修饰基本数据类型时,编译器会报错,assign既可以修饰基本数据类型,也可以修饰对象。
读写权限:readonly、readwrite
readonly:只读权限,一般防止外部修改对应的属性值。开发者可以在实现文件.m中重新声明此属性(默认是readwrite的)以达到访问修改的目的;尽管是只读权限,外部依然可以通过KVC的方式间接访问readonly的属性并修改。
- readonly:只生成 getter 方法
- readwrite:同时生成 getter 和 setter 方法