API Reference对__block变量修饰符有如下几处解释:
//A powerful feature of blocks is that they can modify
variables in the same lexical scope. You signal that a block
can modify a variable using the __block storage type
modifier.
//At function level are __block variables. These are mutable
within the block (and the enclosing scope) and are preserved
if any referencing block is copied to the heap.
大概意思归结出来就是两点:
- __block对象在block中是可以被修改、重新赋值的。
- __block对象在block中不会被block强引用一次,从而不会出现循环引用问题。
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.
使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题,因为苹果文档已经说的很清楚,当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。
因此,__block和__weak修饰符的区别其实是挺明显的:
- __block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
- __weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
- __block对象可以在block中被重新赋值,__weak不可以。
PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
原文章中提到了__unsafe_unretained、__weak等,这都属于属性的声明周期类型。属性的声明周期类型包括:__unsafe_unretained、assign、strong、weak、copy。这些特性决定了存方法将如何处理与其内存相关的内存管理问题。
- assign是默认的也是最简单的:存方法会将传入的值直接赋给实例变量。可以使用assign属性来保存非地向类型的实例变量。对于非对象类型的实例变量来说,默认使用的就是assign属性,因此在属性声明的时候不用显示的添加。
- strong特性,要求保留传入的对象并放弃原有的对象(如果原有对象不再有其他拥有方,就会被释放)。(retain?)凡是指向对象的实例变量,通常都应该使用strong属性(会造成强引用循环的情况下除外)。
- weak特性要求不保留传入的对象。如果该对象被释放,那么相应的实例变量会被自动的赋为 nil。这样做可以避免产生悬空指针。(悬空指针指向的是不再存在的对象。向悬空指针发送消息通常会导致程序崩溃。)相应的存方法会将传入的对象直接赋给实例变量。只能用于修饰对象。
- unsafe_unretained特性与weak特性类似,要求不保留传入的对象。但是,如果该对象被释放的话,相应的实例变量不会被自动的赋为 nil。
- copy特性要求拷贝传入的对象,并将新对象赋给实例变量。copy特性有一个细节问题很容易产生混淆。在下一篇博文里会详细阐述这个问题。