Подтвердить что ты не робот

Как определить, что из контроллера навигации выдается диспетчер навигации?

В настоящее время мне нужно реализовать некоторый код, когда контроллер верхнего уровня выгружается из моего навигационного контроллера. Есть ли способ обнаружить, когда контроллер просмотра выталкивается из стека контроллера навигации?

Насколько это возможно, я хочу держаться подальше от использования viewWillDisappear или viewDidDisappear, потому что я использую splitview в моем проекте, а выбор другой строки в главном представлении также вызывает viewWillDisappear/viewDidDisappear.

4b9b3361

Ответ 1

Вы можете определить, будет ли отображаться представление с использованием свойства isMovingFromParentViewController для контроллера вида, как показано ниже:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
}

isMovingFromParentViewController

Возвращает логическое значение, указывающее, что контроллер представления находится в процесс удаления из родителя.

Ответ 2

ОБНОВЛЕНИЕ 20150430

Основываясь на обратной связи phatmann (первый комментарий ниже), мне было любопытно, если что-то изменилось с тех пор, как я ответил на этот вопрос более года назад. Я собрал простое примерное приложение и получил некоторые интересные результаты.

Вариант 1, пример

https://github.com/greymouser/TestNVC

У меня нет возможности легко тестировать pre-8.x, поэтому я не уверен, что с тех пор что-то изменилось. Однако поведение, которое я изначально описал, все еще происходит. Однако, благодаря объединению тестового приложения, я заметил странность, которой я раньше не был.

Если я просто полагаюсь на {will,did}MoveToParentViewController, я заметил ложный вызов didMoveToParentViewController: при нажатии первого non-rootVC на rootVC с родителем!= nil (подразумевая, что он добавлен, а не удаляется). Я не сталкивался с этим во время моего первоначального ответа, поскольку у меня обычно есть "постоянный" rootVC на моих NVC и не выполнял обратные вызовы. См. Пример приложения с регистрацией, установленной на LOG_WILL_DID_MTPVC (в ViewController.m). Это - отредактировано для пространства - снимок того, что я видел:

TestNVC[] -[vc(rootVC) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]
TestNVC[] -[vc(1) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]  # <-- this is odd
TestNVC[] -[vc(1) didMoveToParentViewController [entering]
...

Мой первоначальный ответ предложил использовать только {will,did}MoveToParentViewController, так как это был "магазин с одним стопом" для обработки этого поведения. Однако теперь, когда я увидел ложный вызов rootVC, я предлагаю сочетание {will,did}MoveToParentViewController, а также стандартные обратные вызовы UINavigationControllerDelegate. Для этого поведения в примере приложения установите logging на LOG_WILL_DID_MTPVC_LEAVING_AND_NVC_WILL_DID_SHOW_VC. Теперь мы видим следующее:

TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[nvcD didShowViewController]: rootVC
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[nvcD willShowViewController]: 2
TestNVC[] -[nvcD didShowViewController]: 2
TestNVC[] -[vc(2) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[vc(2) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[vc(1) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[vc(1) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: rootVC

... и теперь это имеет гораздо больше смысла.

Вариант 2

Другим вариантом, который я не изучил, является использование подкатегории NVC, переопределение - pushViewController:animated: и - popViewControllerAnimated:, а также применение любых действий, которые вы хотите нажать на VC, или VC, который был возвращен из pop. (Обязательно не забудьте вызвать super в своих переопределениях, если вы попытаетесь это сделать.)

Обновить сводку

Итак, спасибо фатманну за возможность переадресовать это. Я думаю, что теперь мой ответ более правильный. Тем не менее, я не уверен, что он был "полностью не правдивым".; -)

ОРИГИНАЛ

Если точное поведение, которое вы описали, является тем, что вы ищете, затем переопределите следующее на контроллере дочернего представления:

- (void)willMoveToParentViewController:(UIViewController *)parent;
- (void)didMoveToParentViewController:(UIViewController *)parent;

willMoveToParentViewController: будет вызван с родителем!= nil при вводе, а parent = nil при выходе. didMoveToParentViewController: всегда будет иметь parent!= nil.

Иногда viewDidDisappear может иметь смысл. Однако, если вы действительно ищете push и pop из родительского контроллера представления контейнера, эти методы выше - то, что вы хотите.

Ответ 3

Для пользователей Swift (Swift 3 - 4.2):

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

но вы можете использовать контроллер навигации Delegates UINavigationControllerDelegate, выполнив следующие действия:

пусть ваш контроллер соответствует UINavigationControllerDelegate:

class ViewController : UIViewController {

      override func viewDidLoad() {
          super.viewDidLoad()
          self.navigationController?.delegate = self
      }

}




extension ViewController : UINavigationControllerDelegate {

     override func willMove(toParentViewController parent: UIViewController?) {

     /*You can detect here when the viewcontroller is being popped*/

     }

}

Надеюсь это поможет. Удачи

Ответ 4

Если вам не нужно знать, прежде чем контроллер представления будет удален, и просто нужно знать, что он был извлечен, вы также можете использовать deinit.

class ViewController: UIViewController {

    deinit {
        // View controller has been popped/dismissed and it being released
    }
}

Этот метод хорошо работает для уведомления координаторов или других делегатов.