arc下的block使用注意事项

  1. block作为属性为什么要用copy修饰,而不用strong

  2. block的循环引用,使用__weak避免循环引用

  3. block的线程安全



1.block作为属性为什么要用copy修饰

       首先要了解:

(1)默认情况下, block的内存是在栈中,它不会对所引用的对象进行任何操作

(2)如果对block做一次copy操作, block的内存就会在堆中,

       block是存档在栈中,生命周期是到栈结束,可能被随时回收,所以需要copy操作,copy之后就转移到堆中了。有人会问,为啥不用strong呢,用strong没有用的原因是,strong仅仅是持有block,让其引用计数加1,block内存还是在栈中,并没有转移到堆中。

<pre name="code" class="objc"><span style="font-size:18px;"><span style="font-family:SimSun;">
typedef void (^MyBlock)(void);
@property (copy) MyBlock callback;
</span>
</span>
 

2.block的循环引用,使用__weak避免循环引用

       什么是循环引用?A持有B,B持有C,C持有B,现在B,C引用计数都是2,C release后因为B还持有C,所以A无法释放,内存泄露,具体情况参考delegate为啥要用weak修饰。

       举个例子,自定义一个TestView,有个block属性,在ViewController里有个TestView的属性testView,testView里的block属性持有了viewcontroller,造成循环引用,解决方法见代码红色部分。

<span style="font-size:18px;">
typedef void(^clickAction)(id obj);
@interface TestView : UIView
@property (copy)clickAction click;
@end

#import "TestView.h"
</span><pre name="code" class="objc"><span style="font-size:18px;">
@interface TestViewController : UIViewController
@property (nonatomic,strong)TestView * testView;
@end
</span>
......
__weak typeof(self) safeSelf = self;
_testView.click = ^(id obj){
[safeSelf test];
};
......


 


2.block的线程安全

       在使用block的时候,我们一般不能肯定在调用block时另一个线程有没有可能去修改block,所以需要声明block的属性为atomic,保证变量的原子性。

           但是,有了atomic来保证基本的原子性还是没有达到线程安全的,接着在调用时需要把block先赋值给本地变量,以防止block突然改变。因为如果不这样的话,即便是先判断了block属性不为空,在调用之前,一旦另一个线程把block属性设空了,程序就会crash,如下代码:

typedef void (^MyblockType)(int);

@property (copy) MyblockType myblock;

if (self.myblock)
{
    //此时,走到这里,self.myblock可能被另一个线程改为空,造成crash
    //注意:atomic只会确保myblock的原子性,这种操作本身还是非线程安全的
    self.myBlock(123);
}

所以正确的代码是(arc):
MyBlockType block = self.myBlock;
//block现在是本地不可变的
if (block)
{
    block(123);
}


在非arc下则需要手动retain一下,否则如果属性被置空,本地变量就成了野指针了,如下代码:
//非arc
MyBlockType block = [self.myBlock retain];
if (block)
{
    block(123);
}
[block release];




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值