Block 中使用成员变量引发crash分析

Block 中使用成员变量引发crash

有如下一段代码块,在执行这段代码时有时候会触发crash

void(^test)() = ^() {
      __strong typeof (weakSelf)strongSelf = weakSelf;
      strongSelf -> _xx = xxx; //引发crash
      strongSelf.yy = yyy;  // 不会引发crash
      [strongSelf doSomething];
      [strongSelf doMoreThing];
}

__weak typeof (self)weakSelf = self;
[self test];

现状:
在self因某些情况被释放掉,变成nil,然后执行blcok体。

结论:
使用使用nil.yyy不会引发crash,使用nil -> _xxx 会引发crash。

解决方案:
在block中__strong后判断strongSelf是否为nil,为空的话直接return

原因:
在block中使用self -> _xxx,如果在执行到block时,self被释放了,在block中就算是使用了__strong typeof () ,这个时候self是nil,并没有强持有self,使用nil -> _xxx 便会引发crash。

详细解释及分析:
在block外使用weak是为了弱引用self,self强引用block,如果在block中在强引用self,会导致死循环。故在声明时使用weak,在block体正式被执行的时候,使用strong,这里主要是为了防止block在执行的过程中,如果self是被弱引用,可能会由于外界失去引用而被释放,导致block中的代码错误执行。

在block执行的时候,执行到strong,如果 WeakSelf 还没有变成 nil,那么就会 retain self,让 self 在 block 执行期间不会变为 nil。这样上面的 doSomething 和 doMoreThing 要么全执行成功,要么全失败,不会出现一个成功一个失败,即执行到中间 self 变成 nil 的情况。

上面的情况之所以会crash,是由于在block执行之前self就被释放了,变成nil,在执行block ,对nil 进行了强以后用,属于无效操作。关于为什么nil -> _xxx会触发而 nil.yyy正常,看注2.

注1:block引用的是weak(self) 里面声明的 weakSelf. 后面使用到的self是strong重新声明的局部变量.

注2:OC有空指针发消息不会崩溃的语言特性,原因是OC的函数调用都是通过objc_msgSend进行消息发送来实现的,相对于C和C++来说,对于空指针的操作会引起Crash的问题,而objc_msgSend会通过判断self来决定是否发送消息,如果self为nil,那么selector也会为空,直接返回,所以不会出现问题。.yyy这种属性的赋值和调用实质上是调用set和get方法,故发送消息没有触发,而直接使用指针赋值触发crash

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值