一,@property修饰属性
1,assign:
assign一般用来修饰基本的数据类型,包括基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char等)
assign声明的属性是不会增加引用计数的,也就是说声明的属性释放后,就没有了,即使其他对象用到了它,也无法留住它,只会crash。
但是,即使被释放,指针却还在,成为了野指针,如果新的对象被分配到了这个内存地址上,又会crash,所以一般只用来声明基本的数据类型,因为它们会被分配到栈上,而栈会由系统自动处理,不会造成野指针。
//assign是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
2,retain:
与assign相对,我们要解决对象被其他对象引用后释放造成的问题,就要用retain来声明。retain声明后的对象会更改引用计数,那么每次被引用,引用计数都会+1,释放后就会-1,即使这个对象本身释放了,只要还有对象在引用它,就会持有,不会造成什么问题,只有当引用计数为0时,就被dealloc析构函数回收内存了。
//retain表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
3,copy:
最常见到copy声明的是NSString。copy与retain的区别在于retain的引用是拷贝指针地址,而copy是拷贝对象本身,也就是说retain是浅复制,copy是深复制,如果是浅复制,当修改对象值时,都会被修改,而深复制不会。
之所以在NSString这类有可变类型的对象上使用,是因为它们有可能和对应的可变类型如NSMutableString之间进行赋值操作,为了防止内容被改变,使用copy去深复制一份。copy工作由copy方法执行,此属性只对那些实现了NSCopying协议的对象类型有效 。
以上三个可以在MRC中使用,但是weak和strong就只能在ARC中使用,也就是自动引用计数,这时就不能手动去进行retain、release等操作了,ARC会帮我们完成这些工作。
//copy表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
4,weak
weak其实类似于assign,叫弱引用,也是不增加引用计数。一般只有在防止循环引用时使用,比如父类引用了子类,子类又去引用父类。IBOutlet(xib生成的对象)、Delegate(代理)一般用的就是weak,这是因为它们会在类外部被调用,防止循环引用。
5,strong:
相对的,strong就类似与retain了,叫强引用,会增加引用计数,类内部使用的属性一般都是strong修饰的,现在ARC已经基本替代了MRC,所以我们最常见的就是strong了。
6,nonatomic:
在修饰属性时,我们往往还会加一个nonatomic,这又是什么呢?它的名字叫非原子访问。对应的有atomic,是原子性的访问。我们知道,在使用多线程时为了避免在写操作时同时进行写导致问题,经常会对要写的对象进行加锁,也就是同一时刻只允许一个线程去操作它。如果一个属性是由atomic修饰的,那么系统就会进行线程保护,防止多个写操作同时进行。这有好处,但也有坏处,那就是消耗系统资源,所以对于iPhone这种小型设备,如果不是进行多线程的写操作,就可以使用nonatomic,取消线程保护,提高性能。
//nonatomic非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic
7,readwrite
readwrite是可读可写特性;需要生成getter方法和setter方法时
8,readonly
readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变
二:浅拷贝和深拷贝
说一下copy和mutableCopy:
copy 浅拷贝,不拷贝对象本身,仅仅是拷贝指向对象的指针。
mutableCopy 深拷贝,是直接拷贝整个对象内存到另一块内存中。
浅拷贝好比你的影子,你死了,影子也没了;深拷贝好比克隆人,你死了,它还在。
注意:和定义的属性为retain和copy时,对字符串赋值深浅拷贝地址变化的区分
牛逼的一句话:
只有不可变对象创建不可变副本(copy)才是浅复制,其它的都是深复制
另外:只有不可变对象创建不可变副本(copy)才是浅复制,其它的都是深复制 这句话没错,深浅只是说的最外层,涉及到容器之类的,外层该深深该浅浅,内部的依旧是浅拷贝,要想都深,则需要遍历。
而retain其实是强迫属性和之前地址保持一致