【问题标题】:Blocks callback crash阻止回调崩溃
【发布时间】:2012-05-20 16:44:37
【问题描述】:

我在 viewControllers 之间的回调中使用 Blocks 而不是委托,但我无法弄清楚为什么这种情况不起作用:

所以我有一个调用 detailViewController 的 mainViewController,当返回作为 mainViewController 上的属性的 tableView 时需要重新加载。

DetailViewController *actionDetail = [[DetailViewController alloc]initWithSaveBlock:^{
        [self.tableView reloadData]  //app crashes here
}];

当用户点击“保存按钮”时,在 detailViewController 中调用“保存”

- (void)save
{
    if (self.saveBlock)
        self.saveBlock();

    [self dismissModalViewControllerAnimated:YES];
}

由于某种原因,[self.tableView reloadData][self dismissModalViewControllerAnimated:YES] 不匹配。如果我删除两者之一,应用程序似乎可以正常工作,显然我错过了预期的行为。

当应用程序崩溃时,控制台中的消息是:

Previous frame inner to this frame (gdb could not unwind past this frame)

有人知道为什么这不起作用吗?

更新: SaveBlock 是这样定义的

typedef void (^SaveBlock)();

@interface DetailViewController : UIViewController
{

}
@property(nonatomic,assign)SaveBlock saveBlock;

【问题讨论】:

  • saveBlock 属性的定义在哪里?我敢打赌是strong/retain 而不是copy,对吧?它必须是copy
  • 不是,我已经更新了问题
  • 分配也不对。它必须是copy

标签: iphone objective-c ios objective-c-blocks


【解决方案1】:

您需要将您的块属性声明为copy

@property(nonatomic, copy) SaveBlock saveBlock;

您不能使用assignstrong。原因是您需要确保拥有自己的块副本。传入的那个可能在一个堆栈帧上,当你开始运行该块时它可能已经消失了。因此,您需要触发Block_copy() 以确保该块被复制到堆中(或者如果它已经存在则保留)。

[注意:这个解释非常简洁。如果您想完全理解它,我建议您阅读有关块运行时的信息。]

【讨论】:

  • 我还有一个问题,使用复制时是否需要释放块(如何?)?
【解决方案2】:

仅适用于 ARC

您需要将块属性声明为strong,将其声明为copy 不需要。所以声明应该是:

@property (nonatomic, strong) SaveBlock saveBlock;

为什么不copy

当传递给您的initWithSaveBlock: 时,该块可能是堆栈分配的,或者它可能不是。无论哪种情况,您都需要保留它。如果块在堆栈上,那么保留它会导致它被复制到堆上。如果块已经在堆上,则不需要复制它。所以使用copy 会起作用,但可能包含一个冗余副本,使用strong 可以避免这种情况。

请参阅this answer 以获得解释。

【讨论】:

  • 如果retain 还没有在堆上,它会在哪里记录copy
  • 在 ARC 中可能是这样(我不知道),但在非 ARC 环境中,retain 不会将其移动到堆中。
  • @CRD Block_copy 经过优化,如果它已经在堆上,则保留它,因此使用复制没有问题。
  • 但是如果使用复制,您不需要了解堆栈和堆块。此外,它定义了复制的语义,它通过复制到堆或仅保留(如果已经在堆上)来做正确的事情。复制是正确的使用方法。
  • 我会说强是错误的。当您以后想要使用它时,必须复制其性质的块。此外,只有在最新的 clang 之后,strong 才做了正确的事情(这与副本完全相同),并且在我能找到的任何地方都没有记录,所以它实际上可能只是一个结果。如果你能找到它说strong now 的文档,那么我很高兴地说我们现在可以使用strong。否则,在这种情况下,副本是唯一使用正确语义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 2019-09-20
  • 1970-01-01
  • 2013-11-05
  • 2012-12-27
相关资源
最近更新 更多