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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您解释一下如何使用Numpy实现Block Statistics工具。 Block Statistics可以在栅格数据上计算一个指定大小的窗口内的统计值,例如平均值、标准差等。以下是一个使用Numpy实现Block Statistics的示例代码: ```python import numpy as np import rasterio # 读取栅格数据 with rasterio.open('input.tif') as src: data = src.read(1) # 定义窗口大小和统计函数 window_size = 3 statistics_function = np.mean # 定义滑动窗口函数 def sliding_window(arr, window_size): """ 滑动窗口函数,返回窗口内数据 """ for i in range(arr.shape[0]-window_size+1): for j in range(arr.shape[1]-window_size+1): yield arr[i:i+window_size, j:j+window_size] # 计算统计值 result = np.zeros_like(data) for i, window in enumerate(sliding_window(data, window_size)): result[i//data.shape[1], i%data.shape[1]] = statistics_function(window) # 保存结果 with rasterio.open('output.tif', 'w', **src.profile) as dst: dst.write(result, 1) ``` 在这个示例,我们首先使用rasterio库读取了输入的栅格数据。然后,我们定义了窗口大小和统计函数。接下来,我们定义了一个滑动窗口函数,用于在栅格数据上滑动一个指定大小的窗口。最后,我们使用一个循环来计算每个窗口内的统计值,并将结果保存为一个新的栅格数据。 注意,在实际应用,您可能需要根据具体的需求对代码进行适当的修改。例如,您可能需要考虑边界效应等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值