iOS 5 блокирует сбой только с Release Build

Я использовал блоки и ARC, и обнаружил, что в некоторых случаях iOS вылетает только в Release build. Это был неправильный способ написания кода, вот так.

-(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, чтобы мы могли найти этот тип ошибок раньше.

Еще один вопрос: "Есть ли какая-либо настройка сборки, которая приводит к сбою кода при отладочной сборке?"

Вы можете запустить пример кода из gitHub, https://github.com/tomohisa/iOS_PopoverMenu_Notification

Посмотрите ViewController.m и найдите закомментированный код (только сбой при выпуске).

1 ответ

Решение

Вы правы, что вам нужно добавить [block copy], Это потому, что этот блок создается в текущем кадре стека (т.е. в clickedButtonA:event:) но затем вы добавляете его в словарь и, вероятно, вытащите его позже. Когда вы извлекаете его позже и используете его, этот оригинальный кадр стека исчезает, и у вас будет указатель на некоторую случайную память, которая может (скорее всего, не будет) фактически больше не быть блоком.

Когда вы копируете блок, если он в данный момент находится в стеке, он копируется в кучу, а если он уже находится в куче, то он просто сохраняет его. Это означает, что теперь у вас есть блок, который можно передавать между контекстами и он будет действительным.

Причина, по которой вы видите сбой только в режиме выпуска, заключается в том, что в режиме выпуска будет включена оптимизация компилятора, которая полностью изменит способ обработки стека. Вероятно, вам очень повезло в режиме отладки, чтобы не увидеть проблему, и вы просто придумали, как разрабатывается ваше приложение.

Другие вопросы по тегам