PrepareForSegue не вызывается после performSegue: withIdentifier: с popover style

У меня есть универсальное приложение, где я использую один и тот же контроллер для раскадровки IPad и IPhone. Я положил UILongPressGestureRecognizer на UITableView, что, когда ячейка нажата на iPhone, она вызывает действие, выполняющее segue:

-(IBAction)showDetail:(id)sender {
    UILongPressGestureRecognizer *gesture = (UILongPressGestureRecognizer*)sender;
    if (gesture.state == UIGestureRecognizerStateBegan) {
        CGPoint p = [gesture locationInView:self.theTableView];

        NSIndexPath *indexPath = [self.theTableView indexPathForRowAtPoint:p];
        if (indexPath != nil) {
            [self performSegueWithIdentifier:SEGUE_DETAIL sender:indexPath];
        }
    }
}

segue представляет собой подробное представление, выполненное как "push". Первое, что вы должны заметить, это то, что отправитель является NSIndexPath, это единственный способ, которым я нашел для передачи выбранной ячейки. Может быть, есть лучшее решение. Все работает отлично, в некотором смысле, что выполняется segue, и до того, как будет вызвана команда prepareForSegue.

Однако бывает, что на iPad я изменил идентификатор segue на Popover. Теперь все работает частично, выполняется segue, но prepareForSegue не вызывается, поэтому контроллер представления назначения не настроен, как и должно быть.

Что я делаю неправильно?

Ответ 1

То, что я обнаружил до сих пор, заключается в том, что с любым идентификатором segue, который не является popover, это invocations, сделанные iOS:

  • prepareForSegue (на контроллере источника)
  • viewDidLoad (на контроллере назначения)

в то время как в popover segue порядок вызова:

  • viewDidLoad (на контроллере назначения)
  • prepareForSegue (на контроллере источника)

только потому, что я поместил всю свою логику в viewDidLoad, контроллер не был правильно инициализирован, и произошел сбой. Так что это не совсем так, что prepareForSegue не вызывается, правда в том, что я получаю исключение, и я ошибочно ошибаюсь, поскольку prepareForSegue не получает вызов.

Я не мог поместить все в viewWillAppear, потому что должен был быть вызван вызов CoreData, и я не хотел проверять, поддерживаются ли сущности каждый раз при отображении представления.

Как я решил это? Я создал другой метод в контроллере назначения

-(void)prepareViewController {
  // initialization logic...
}

и изменение метода prepareForSegue в самом исходном контроллере:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  MyViewController *mvc = (MyViewController*)[segue destinationViewController];
  // passing variable 
  // with segue style other than popover this called first than viewDidLoad
  [email protected]"prop1"; 
  [email protected]"prop2";

  // viewWillAppear is not yet called
  // so by sending message to controller
  // the view is initialized
  [mvc prepareViewController];

}

Не знаю, будет ли это ожидаемое поведение с popover, так или иначе, теперь все работает.

Ответ 2

Я заметил, что код плиты котла для шаблона Master-Detail Xcode (iPhone) использует следующий шаблон для настройки подробного просмотра VC:

  • подробные настройки VC (для свойств) перезаписываются для вызова метода configureView (configureView будет обновлять все ваши элементы управления в представлении, например, метки и т.д.).
  • Подробный метод VC viewDidLoad также вызывает метод configureView

Я не последовал этому шаблону на днях, когда пытался переустановить подробный VC в своем приложении для фильма, и это вызвало у меня проблемы.

У меня нет большого опыта с popovers; однако, если вышеприведенный шаблон используется с детальным VC, который отображается внутри popover, то не будет ли конфигурация детализации VC настроена при настройке подробных свойств VC из метода prepareForSegue?