今天在开发LemonBest开源项目的时候,写了一个小demo,遇到一个大坑,在LemonBestItem中我采用属性的方式进行保存一个回调block,在点击之后调用这个block,代码如下:

@interface LemonBestItem : NSObject

typedef void(^ LK_ACION_SHEET_ON_ITEM_TOUCH)(LemonBestItem *item);

/// @brief 点击事件
@property (assign) LK_ACION_SHEET_ON_ITEM_TOUCH action;
// xxxx其他若干代码

@end

刚开始在传入属性的block的函数体中只是写了一个NSLog(@"OK")运行,没问题,可是当我在block中操作外界的变量时候,出现了问题,代码很简单,我只是改了一个Label的文字:

[as addAction: [[LemonBestItem alloc] initWithTitle:@"第一项" onTouchBlock:^(LemonBestItem *item) {
    // 我只是在block中执行的下面这行代码,改变text值 
    self.valueLabel.text = @"value 1";
}] groupIndex: 1];

马上应用就挂掉了,提示:

Thread1: EXC_BAD_ACCESS(code=1,address=0x20)

通常EXC_BAD_ACCESS错误产生的原因是向未被初始化、或者已经被回收的内存发送消息,那我这是怎么回事?本来Block就是我的弱项,心中默念,这个问题解决完一定要找时间恶补一下Block相关的知识!!!

既然问题出了,就得调试啊,本身对Block就一知半解,只能像一只无头的苍蝇一样乱撞,慢慢来吧~

首先,给block中的text修改值的那一行代码前面打了个断点,想po一下看看是不是self.valueLabel 被销毁了?

unity-tweak-tool

然而断点还没执行,应用就又挂掉了!!!正在发呆时候突然发现页面一下跳到了调用block的所在地方(刚才第一次崩溃的时候脑残了怎么没有发现跳到这里崩溃的!)

unity-tweak-tool

总算有点眉目了,原来是action这个block对象被销毁了!那么接下来怎么解决呢?经过一番查资料、试验,终于解决了,大家先看一下最后代码的样子,然后我再给大家讲一下为什么这么做。

把刚才把Block作为属性的地方修改成如下:

@interface LemonBestItem : NSObject

typedef void(^ LK_ACION_SHEET_ON_ITEM_TOUCH)(LemonBestItem *item);

/// @brief 点击事件 - 存储block作为属性要记得用copy,而不是assign
@property (atomic,copy) LK_ACION_SHEET_ON_ITEM_TOUCH action;

// xxx 其他代码

@end

然后把调用回调Block的地方修改成这样:

- (void)onTouchUpInside{
    LK_ACION_SHEET_ON_ITEM_TOUCH actionBlock = self->_item.action;
    if (actionBlock) {
        actionBlock(self->_item);
    }
}

接下来,我们说一说为什么这么改哈~

  • 为什么属性要改成@property (atomic,copy)

    答:因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,同时为了保证属性的原子性,所以设置了atomic。

  • 为什么在调用block前先保存了一下对象?即LK_ACION_SHEET_ON_ITEM_TOUCH actionBlock = self->_item.action;不是已经判断if(actionBlock)了吗?

    答:因为if(actionBlock)只能保证在你执行if判断时候你的actionBlock不为空,可是有可能在你执行完if判断后被其他线程中的操作修改掉actionBlock的哦!所以为了保证线程安全,我们先创建一个临时的变量来保存我们的block,然后再if判断和调用,以保证我们的block不会因为被其他线程临时修改而crash掉哦~

怎么样,你的程序中还有block相关的问题吗,来一起交流交流,正好我也学习学习,自己心里很清楚,block这里是时候该恶补一下啦~

#### 如果你还是有不懂得东西,你可以加我QQ哦,我来教你:188443213

欢迎您关注我的公众号,柠檬软件,每天推送各种比较亲民的技术文章,感谢您的支持

unity-tweak-tool

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐