关于iOS中strong,weak,retain,assign,copy,nomatic

iOS 5之后添加了ARC的特性,顺便提出来新的strong、weak关键字。相比而言,retain和strong是一致的(声明为强引用);assign和weak是基本一致的(声明为弱引用)。

之所以说它俩是基本一致是因为它俩还是有所不同的,weak严格的说应当叫“归零弱引用”,即当对象被销毁后,会自动的把它的指针置为nil,这样可以防止野指针错误。而assign销毁对象后不会把该对象的指针置nil,对象已经被销毁,但指针还在痴痴的指向它,这就成了野指针,这是比较危险的。

1、引用计数

在ObjC中每个对象内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的allocretainnewcopy方法之后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。

2、内容与场景
关键字 内容 场景
assign 默认类型,setter方法直接赋值,不进行任何retain操作,不改变引用计数 对基础数据类型(NSInteger)和C数据类型(int,float,double,char等)
retain 释放旧的对象(release),将旧对象的值赋给新对象,再令新对象引用计数为1 对其他NSObject和其子类
copy 与retain处理流程一样,先对旧值release,再copy出新的对象,retainCount为1. 对NSString
nonatomic 非原子性访问,对属性赋值的时候不加锁,多线程并发访问会提高性能 如果不加此属性,则默认是两个访问方法都为原子型事务访问

【注】对copy属性要特别注意:被定义有copy属性的对象必须要 符合NSCopying协议,必须实现- (id)copyWithZone:(NSZone *)zone方法。

具体一点:IBOutlet可以为weak,NSString为copy,Delegate一般为weak,其他的看情况。一般来说,类“内部”的属性设置为strong,类“外部”的属性设置为weak。说到底就是一个归属权的问题。小心出现循环引用导致内存无法释放。

3、比较

|strong vs weak |
| :--- -------------|
| strong:强引用,也是我们通常说的引用,其存亡直接决定了所指向对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示在列表中,则此对象会被从内存中释放|
| weak:弱引用,不决定对象的存亡。即使一个对象被持有无数个弱引用,只要没有强引用指向它,那么还是会被清除 |
|strong与retain功能相似;weak与assign相似,只是当对象消失后weak会自动把指针变为nil,防止野指针|
【注】有一种情况你需要使用weak(默认是strong),就是为了避免retain cycles(就是父类中含有子类{父类retain了子类},子类中又调用了父类{子类又retain了父类},这样都无法release)

|copy vs retain |
| :--- -------------|
| copy其实是建立了一个相同的对象,而retain不是|
|copy是内容拷贝,retain是指针拷贝|
|copy是内容的拷贝 ,对于像NSString,的确是这样,如果拷贝的是NSArray,这时只是copy了指向array中相对应元素的指针.这便是所谓的"浅复制"|
【注】copy是在你不希望a和b共享一块内存时会使用到,a和b各自有自己的内存。

|强引用 vs 弱引用 |
| :--- -------------|
| 强引用:当前对象被其他对象引用时,会执行retain操作,引用计数器+1。当retainCount=0时,该对象才会被销毁。因为我们要进行对象的内存管理,所以这是默认的引用方式。(默认是强引用)|
|弱引用:当前对象的生命周期不被是否由其他对象引用限制,它本该什么时候销毁就什么时候被销毁。即使它的引用没断,但是当它的生存周期到了时就会被销毁。|
【注】在定义属性时,若声明为retain类型的,则就是强引用;若声明为assign类型的,则就是弱引用。后来内存管理都由ARC来完成后,若是强引用,则就声明为strong;若是弱引用,则就声明为weak。

|__block和__weak修饰符|
| :--- -------------|
|__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型|
|__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)|
|__block可以在block对象中被重新赋值 (_weak不可以) |

推荐阅读更多精彩内容