ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?
atomic、readwrite、strong(对象)、assgin(基本数据类型)。
具体比较分析:
1、atomic与nonatomic
atomic:默认是有该属性的,这个属性是为了保证程序在多线程情况下,编译器会自动生成一些加锁代码,避免该变量的读写不同步的问题,提供多线程安全。
nonatomic:如果该对象无需考虑多线程的情况,加入这个属性,这样会让编译器少生成一些加锁代码,禁止多线程,变量保护,提高性能和效率。
注:atomic是Objc使用的一种线程保护技术,基本上来讲是防止在写未完成的时候另一个线程读取,造成的数据错误。而这种机制是非常耗费系统资源的,所以iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。而iOS开发中,普遍使用nonatomic也是基于性能这一点。
扩展:
自旋锁和互斥锁
共同点: 都可以锁定一段代码。同一时间,只有线程能够执行这段锁定的代码。
区别:互斥锁,在锁定的时候,其他线程会睡眠,等待条件满足,再唤醒。
自旋锁,在锁定的时候,其他的线程会做死循环,一直等待这条件满足,一旦条件满足,立马去执行,少了一个唤醒过程。
2、readwrite与readonly
readwrite:这个属性是默认的情况,会自动为你生成存取器。
readonly:只生成getter,不会生成setter方法。
注:
readwrite、readonly这两个属性的真正价值,不是提供成员变量的访问接口,而是控制成员变量的访问权限。
3、strong与weak
strong:强引用,也是我们通常说的引用,其存亡直接决定了所指向对象的存亡,当强引用指向了某个对象,那便拥有了这个对象。如果不存在指向一个对象的引用,并且此对象不再使用,则对象就会被从内存中释放掉。默认所有实例变量和局部变量都是strong指针。
weak:弱引用,不决定对象的存亡,只是单纯的引用了某个对象但是并不拥有该对象。即使一个对象被持有无数个弱引用,只要没有强引用指向它,那么还是会被清除。
注:
strong与retain功能相似;weak与assign相似,只是当对象消失后weak会自动把指针置为nil,避免了野指针的产生,因而weak属性就不需要在dealloc中置nil了。
4、assign和weak
weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
weak 必须用于 OC 对象,而assign 可以用非 OC 对象。
使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)
注:
1.修饰变量类型的区别
weak只可以修饰对象。如果修饰基本数据类型,编译器会报错-“Property with ‘weak’ attribute must be of object type”。
assign可修饰对象,和基本数据类型。当需要修饰对象类型时,MRC时代使用unsafe_unretained。当然,unsafe_unretained也可能产生野指针,所以它名字是"unsafe_”。
2.是否产生野指针的区别
weak不会产生野指针问题。因为weak修饰的对象释放后(引用计数器值为0),指针会自动被置nil,之后再向该对象发消息也不会崩溃。 weak是安全的。
assign如果修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。修饰的对象释放后,指针不会自动被置空,此时向对象发消息会崩溃。
assign适用于基本数据类型如int,float,struct等值类型,不适用于引用类型。因为值类型会被放入栈中,遵循先进后出原则,由系统负责管理栈内存。而引用类型会被放入堆中,需要我们自己手动管理内存或通过ARC管理。
weak适用于delegate和block等引用类型,不会导致野指针问题,也不会循环引用,非常安全。
5、copy和retain
assgin:默认类型,setter方法直接赋值,不进行任何的retain操作,不改变引用计数。一般用来处理基本数据类型。
retain:释放旧的对象(release),将旧对象的值赋给新对象,再令新对象引用计数为1。可理解为指针拷贝。
copy:与retain的流程一样,先对旧的值release,再copy出新的对象,引用计数为1,为了减少对上下文的依赖而引入的机制。可以理解为内容的拷贝,也就意味着内容被copy后,内存中会有两个存储空间存储同样的内容。
对copy属性要特别注意:被定义有copy属性的对象必须要 符合NSCopying协议,必须实现- (id)copyWithZone:(NSZone *)zone方法。对copy属性要特别注意:被定义有copy属性的对象必须要 符合NSCopying协议,必须实现- (id)copyWithZone:(NSZone *)zone方法。
对于不可变对象来说,copy为浅拷贝,和strong一样,均增加了源对象的引用计数;而对于可变对象来说,copy为深拷贝,我们知道深拷贝为内容拷贝,所以如果改变源对象时,声明成copy的属性并不会跟着变化。而由于声明成strong的属性只是增加源对象的引用计数,依旧指向源对象,故会同步改变。所以,当我们声明属性时,如果不希望它因为源对象(源对象为可变对象时)的改变而改变,则用copy修饰。
扩展
深拷贝与浅拷贝
深拷贝就是内容拷贝,浅拷贝就是指针拷贝
其实copy本质是用来做深拷贝的,但是修饰不可变的数组时,由于深拷贝出来也不能做添加或删除操作,为了节约资源,直接浅拷贝了。
深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。
浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象。
[immutableObject copy] //浅复制
[immutableObject mutableCopy] //单层深复制
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制