Проверка, собирается ли UIViewController получить Popped из стека навигации? - PullRequest
55 голосов
/ 13 марта 2009

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

Я не могу использовать -viewWillDisappear, потому что он вызывается, когда контроллер представления перемещается из экрана по ЛЮБОЙ причине (например, новый контроллер представления помещается сверху).

Мне конкретно нужно знать, когда контроллер сам будет отключен.

Любые идеи будут замечательными, заранее спасибо.

Ответы [ 12 ]

75 голосов
/ 07 марта 2012

Переопределите метод viewWillDisappear в представленном VC, затем проверьте флаг isMovingFromParentViewController в пределах переопределения и выполните определенную логику. В моем случае я скрываю панель инструментов навигационных контроллеров. Все еще требует, чтобы ваш представленный VC понимал, что он выдвинут, хотя и не идеален.

24 голосов
/ 25 октября 2013

Попробуйте переопределить willMoveToParentViewController: (вместо viewWillDisappear:) в своем пользовательском подклассе UIViewController.

Вызывается непосредственно перед добавлением или удалением контроллера представления из контроллера представления контейнера.

- (void)willMoveToParentViewController:(UIViewController *)parent
{
    [super willMoveToParentViewController:parent];
    if (!parent) {
        // `self` is about to get popped.
    }
}
18 голосов
/ 29 июня 2013

К счастью, к тому времени, когда вызывается метод viewWillDisappear, viewController уже удален из стека, поэтому мы знаем, что viewController выталкивает, потому что его больше нет в self.navigationController.viewControllers

Swift 4

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if let nav = self.navigationController {
        let isPopping = !nav.viewControllers.contains(self)
        if isPopping {
            // popping off nav
        } else {
            // on nav, not popping off (pushing past, being presented over, etc.)
        }
    } else {
        // not on nav at all
    }
}

Оригинальный код

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if ((self.navigationController) && 
        (![self.navigationController.viewControllers containsObject:self])) {
        NSLog(@"I've been popped!");
    }
}
12 голосов
/ 10 февраля 2010

Это работает для меня.

- (void)viewDidDisappear:(BOOL)animated
{
    if (self.parentViewController == nil) {
        NSLog(@"viewDidDisappear doesn't have parent so it's been popped");
        //release stuff here
    } else {
        NSLog(@"PersonViewController view just hidden");
    }
}
10 голосов
/ 13 марта 2009

Я не думаю, что для этого есть явное сообщение, но вы можете создать подкласс UINavigationController и переопределить его - popViewControllerAnimated (хотя я не пробовал это раньше)

В качестве альтернативы, если нет других ссылок на контроллер представления, не могли бы вы добавить к нему - dealloc?

8 голосов
/ 03 мая 2009

Вы можете поймать это здесь.

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

    if (viewController == YourAboutToAppearController) {
            // do something
    }
}

Это сработает непосредственно перед отображением нового вида. Никто еще не переехал. Я все время использую магию перед asinine NavigationController. Вы можете устанавливать заголовки и заголовки кнопок и делать там что угодно.

3 голосов
/ 18 сентября 2010

У меня такая же проблема. Я попытался с viewDisDisappear, но у меня нет вызова функции :( (не знаю почему, может быть, потому что все мои VC является UITableViewController). Предложение Алекса работает нормально, но не работает, если ваш контроллер навигации отображается на вкладке «Дополнительно». В этом случае все виртуальные контроллеры ваших контроллеров навигации имеют навигационный контроллер как UIMoreNavigationController, а не контроллер навигации, который вы вложили в подклассы, поэтому навигация не будет уведомлять вас, когда виртуальный контроллер собирается отключиться. Наконец, я решил проблему с категорией UINavigationController, просто переписать - (UIViewController *) popViewControllerAnimated: (BOOL) animated

- (UIViewController *)popViewControllerAnimated:(BOOL)animated{
   NSLog(@"UINavigationController(Magic)");
   UIViewController *vc = self.topViewController;
   if ([vc respondsToSelector:@selector(viewControllerWillBePopped)]) {
      [vc performSelector:@selector(viewControllerWillBePopped)];
   }
   NSArray *vcs = self.viewControllers;
   UIViewController *vcc = [vcs objectAtIndex:[vcs count] - 2];
   [self popToViewController:vcc animated:YES];
   return vcc;}

У меня хорошо работает: D

2 голосов
/ 31 марта 2011

Я пробовал это:

- (void) viewWillDisappear:(BOOL)animated {
    // If we are disappearing because we were removed from navigation stack
    if (self.navigationController == nil) {
        // YOUR CODE HERE
    }

    [super viewWillDisappear:animated];
}

Идея состоит в том, что при выталкивании навигационный контроллер контроллера представления устанавливается в ноль. Поэтому, если представление должно было исчезнуть, и у него больше был навигационный контроллер, я пришел к выводу, что оно появилось. (может не работать в других сценариях).

Не могу поручиться, что viewWillDisappear будет вызываться при появлении сообщения, поскольку это не упоминается в документации. Я попробовал это сделать, когда вид был сверху, а снизу сверху - и он работал в обоих случаях.

Удачи, Одед.

1 голос
/ 28 января 2017

Подкласс UINavigationController и переопределение popViewController:

Свифт 3

protocol CanPreventPopProtocol {
    func shouldBePopped() -> Bool
}

class MyNavigationController: UINavigationController {
    override func popViewController(animated: Bool) -> UIViewController? {
        let viewController = self.topViewController

        if let canPreventPop = viewController as? CanPreventPopProtocol {
            if !canPreventPop.shouldBePopped() {
                return nil
            }
        }
        return super.popViewController(animated: animated)
    }

    //important to prevent UI thread from freezing
    //
    //if popViewController is called by gesture recognizer and prevented by returning nil
    //UI will freeze after calling super.popViewController
    //so that, in order to solve the problem we should not return nil from popViewController
    //we interrupt the call made by gesture recognizer to popViewController through
    //returning false on gestureRecognizerShouldBegin
    //
    //tested on iOS 9.3.2 not others
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        let viewController = self.topViewController

        if let canPreventPop = viewController as? CanPreventPopProtocol {
            if !canPreventPop.shouldBePopped() {
                return false
            }
        }

        return true
    }

}
1 голос
/ 03 июля 2015

Вы можете использовать это:

if(self.isMovingToParentViewController)
{
    NSLog(@"Pushed");
}
else
{
    NSLog(@"Popped");
}
...