在使用block 时,为避免亲戚循环引用问题,我们一般常将外部变量用 __weak 或者 __block 关键字进行修饰。
__block和__weak修饰符的区别:
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题,因为苹果文档已经说的很清楚,当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。
PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
API Reference对__weak变量修饰符有如下几处解释:
__weak specifies a reference that does not keep the
referenced object alive. A weak reference is set to nil when
there are no strong references to the object.
1.__block对象在block中是可以被修改、重新赋值的。
2.__block对象在block中不会被block强引用一次,从而不会出现循环引用问题。
在ARC环境下,我们常常会使用weak 的修饰符来修饰一个变量,防止其在block中被循环引用,但是有些特殊情况下,我们在block中又使用strong 来修饰这个在block外刚刚用__weak修饰的变量,例如如下:
在block中调用self会引起循环引用,但是在block中需要对weakSelf进行
strong,保证代码在执行到block中,self不会被释放,当block执行完后,
会自动释放该strongSelf;
1.如果仅仅使用__weak去修饰变量,当别处把变量释放后,block中该变量也会被释放掉
2.当加上修饰符strong时,当别处把变量释放掉,但调用该变量的block如果仍然没有执行结束,那么系统就会等待block执行完成后再释放,对该变量在block中的使用起到了保护作用。当block执行结束后会自动释放掉。
原文章中提到了__unsafe_unretained、__weak等,这都属于属性的声明周期类型。属性的声明周期类型包括:__unsafe_unretained、assign、strong、weak、copy。这些特性决定了存方法将如何处理与其内存相关的内存管理问题。
- assign是默认的也是最简单的:存方法会将传入的值直接赋给实例变量。可以使用assign属性来保存非地向类型的实例变量。对于非对象类型的实例变量来说,默认使用的就是assign属性,因此在属性声明的时候不用显示的添加。
- strong特性,要求保留传入的对象并放弃原有的对象(如果原有对象不再有其他拥有方,就会被释放)。(retain?)凡是指向对象的实例变量,通常都应该使用strong属性(会造成强引用循环的情况下除外)。
- weak特性要求不保留传入的对象。如果该对象被释放,那么相应的实例变量会被自动的赋为 nil。这样做可以避免产生悬空指针。(悬空指针指向的是不再存在的对象。向悬空指针发送消息通常会导致程序崩溃。)相应的存方法会将传入的对象直接赋给实例变量。只能用于修饰对象。
- unsafe_unretained特性与weak特性类似,要求不保留传入的对象。但是,如果该对象被释放的话,相应的实例变量不会被自动的赋为 nil。
- copy特性要求拷贝传入的对象,并将新对象赋给实例变量。copy特性有一个细节问题很容易产生混淆。