iOS 5仅使用Release Build阻止崩溃

时间:2012-04-21 21:21:15

标签: ios automatic-ref-counting objective-c-blocks

我使用了块和ARC,并且在某些情况下发现,iOS仅在Release版本中崩溃。编写代码是错误的方式,就像这样。

-(IBAction)clickedButtonA:(UIBarButtonItem*)sender event:(UIEvent*)event {
  NSMutableArray *arrRows = [NSMutableArray arrayWithCapacity:0];
  #warning this code only crash on Release Build.... Don't use this
  NSMutableDictionary * dicRow = [NSMutableDictionary dictionaryWithCapacity:0];
  [arrRows addObject:dicRow];
  dispatch_block_t block = ^{
    NSString *str = [NSString stringWithFormat:@"%@",[_tweet valueForKey:@"text"]];
    [[UIPasteboard generalPasteboard] setString:str];
  };
  [dicRow setValue:block forKey:kDicKeyLinkPopBlock];

  NSMutableArray *sections = [NSMutableArray arrayWithObject:arrRows];
  TOVLinkPopoverViewController *controller= [[TOVLinkPopoverViewController alloc] init];
  controller.arrayLink = sections;
}

从其他控制器,当我访问该块时,它崩溃只有我在发布版本。我知道你需要复制块

[dicRow setValue:[block copy] forKey:kDicKeyLinkPopBlock];

对于非块感知类,如NSMutableDictionary。

问题是“为什么它只会在发布版本上崩溃?”我知道这应该“崩溃”,这是使用块的错误方法,但希望它在Debug构建时崩溃,所以我们可以更早地找到这种bug。

还有一个问题是“是否存在任何使用调试版本使代码崩溃的构建设置?”

您可以从gitHub运行示例代码, https://github.com/tomohisa/iOS_PopoverMenu_Notification

请参阅ViewController.m并查找已注释掉的代码(仅在发布时崩溃)。

1 个答案:

答案 0 :(得分:6)

您需要添加[block copy]。这是因为该块是在当前堆栈帧中创建的(即在clickedButtonA:event:内),但随后您将其添加到字典中,并可能稍后将其拉出。当您稍后将其拉出并使用它时,原始堆栈帧已经消失,您将有一个指向某些随机内存的指针,这些内存可能不再(很可能不会)实际上是该块。

当你复制块时,如果它当前在堆栈上,那么它会被复制到堆中,如果它已经在堆上,那么它就会保留它。这意味着您现在拥有一个可以在上下文之间传递并且有效的块。

您只是看到它在发布模式下崩溃的原因是因为发布模式将启用编译器优化,这完全改变了堆栈的处理方式。可能你在调试模式下非常幸运,没有看到问题,只是对你的应用程序设计的一个怪癖。