首先要理解Block和__block变量的本质。
Block === 栈上结构体实例
__block === 栈上__block结构体实例
截获__block变量对象
在arc中, __block修饰的变量会引用到,并且计算+1
在非arc中,__block修饰的变量的引用计算是不变的。
非arc下可使用(arc直接使用__weak即可)
ARC下Block何时会从栈自动被复制到推, 以及__block和__weak的使用问题
由于Block是默认建立在栈上, 所以如果离开方法作用域, Block就会被丢弃, 在非ARC情况下, 我们要返回一个Block ,需要 [Block copy];
对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中实用的对象:
__block id blockSelf=self;
self.blk=^{
NSLog(@"%@",blockSelf); //在非ARC下对于栈上的_block对象, Block不会对其复制, 仅仅使用, 不会增加引用计数.
};
对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中实用的对象:
__weak id weakSelf=self;
self.blk=^{
NSLog(@"%@",weakSelf);
};
如果要在ARC下, 为了防止循环引用, 使用__block来修饰在Block中实用的对象,仍然会被retain, 所以需要多做一些设置
__block id blockSelf=self;
self.blk=^{
NSLog(@"%@",blockSelf);
self.blk=nil; //blk被释放, blk只有的blockSelf也就被释放了
};
blk(); //并且一定要运行一次, 否则不能被释放
这样就使blk断开了与blockSelf的持有关系.
这么多好处是可以自己控制对self的持有时间.
不过在最新的ios版本中, 这些会始终被已叹号形式提示存在循环引用问题.
这种书写方式不被推荐. 除非你要在block中修改__block的指针指向.
其实我们用使用__weak修饰符, 只是不能修改对象本身, 但是可以修改对象的属性.
自我总结一下就是:
1,在MRC 时代,__block 修饰,可以避免循环引用;ARC时代,__block 修饰,同样会引起循环引用问题;
2,__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型;
3,__weak只能在ARC模式下使用,也只能修饰对象,不能修饰基本数据类型;
4,__block对象可以在block中被重新赋值,__weak不可以;
5,__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。(__weak 会自动置为nil)