Как идентифицировать предыдущий контроллер представления в стеке навигации

У меня 2 отдельных navigationcontrollersодин с RootViewController А другой с RootViewController B.

Я умею толкать ViewController C на навигационный стек A или B.

Вопрос: когда я в ViewController C, как я могу узнать, нахожусь ли я в стеке, принадлежащем A или B?

17 ответов

Решение

Вы могли бы использовать UINavigationController"s viewControllers имущество:

@property(nonatomic, copy) NSArray *viewControllers

Обсуждение: корневой контроллер представления находится в индексе 0 в массиве, контроллер заднего обзора находится в индексе n-2, а верхний контроллер находится в индексе n-1, где n - количество элементов в массиве.

https://developer.apple.com/documentation/uikit/uinavigationcontroller

Вы можете использовать это, чтобы проверить, является ли корневой контроллер представления (тот с индексом массива 0) контроллером представления A или B.

Вот реализация принятого ответа:

- (UIViewController *)backViewController
{
    NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;

    if (numberOfViewControllers < 2)
        return nil;
    else
        return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}
- (UIViewController *)backViewController
{
    NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];

    if ( myIndex != 0 && myIndex != NSNotFound ) {
        return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
    } else {
        return nil;
    }
}

Более общая реализация принятого ответа:

- (UIViewController *)backViewController {
    NSArray * stack = self.navigationController.viewControllers;

    for (int i=stack.count-1; i > 0; --i)
        if (stack[i] == self)
            return stack[i-1];

    return nil;
}

Это вернет правильный "контроллер заднего вида" независимо от того, где текущий класс находится в стеке навигации.

Вот модифицированная версия кода Swift Прабху Бимана, которая адаптирует его для поддержки Swift 3:

extension UIViewController {
    func backViewController() -> UIViewController? {
        if let stack = self.navigationController?.viewControllers {
            for i in (1..<stack.count).reverse() {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}

Быстрая реализация кода tjklemz в качестве расширения:

extension UIViewController {

    func backViewController() -> UIViewController? {        
        if let stack = self.navigationController?.viewControllers {
            for(var i=stack.count-1;i>0;--i) {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}

Как UINavigationController расширение:

extension UINavigationController {

    func previousViewController() -> UIViewController? {
        guard viewControllers.count > 1 else {
            return nil
        }
        return viewControllers[viewControllers.count - 2]
    }

}

Доступ к n-2 элемент viewControllers свойство для доступа к родительскому контроллеру представления.

Когда у вас есть этот экземпляр, вы можете проверить его тип, регистрируя, что выходит из NSStringFromClass() функция. Или вы могли бы сохранить некоторые static const строка идентификатора в контроллерах A и B и функция получения, которая выводит строку.

Быстрая реализация кода @tjklemz:

var backViewController : UIViewController? {

        var stack = self.navigationController!.viewControllers as Array

        for (var i = stack.count-1 ; i > 0; --i) {
            if (stack[i] as UIViewController == self) {
                return stack[i-1] as? UIViewController
            }

        }
        return nil
    }

Более краткая импровизация Свифта:

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let nav = self.navigationController,
              let myIdx = nav.viewControllers.index(of: self) else {
            return nil
        }
        return myIdx == 0 ? nil : nav.viewControllers[myIdx-1]
    }
}

Потому что мертвые лошади любят быть побежденными:)

- (UIViewController *)previousViewController
{
    NSArray *vcStack = self.navigationController.viewControllers;
    NSInteger selfIdx = [vcStack indexOfObject:self];
    if (vcStack.count < 2 || selfIdx == NSNotFound) { return nil; }
    return (UIViewController *)[vcStack objectAtIndex:selfIdx - 1];
}

Использовать navigationController способ получить его. Смотрите документацию на сайте Apple.

navigationController Родитель или предок, который является контроллером навигации. (Только для чтения)

@property (неатомный, только для чтения, сохранить) UINavigationController *navigationController

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

Доступность Доступно в iOS 2.0 и более поздних версиях.

Найти предыдущий вид контроллера просто.

В вашем случае, т. Е. Вы находитесь в C, и вам нужно B, [self.navigationController.viewControllers lastObject] это то, что вы хотите.

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

Со Свифтом используя охрану.

extension UIViewController {

    func getPreviousViewController() -> UIViewController? {
        guard let _ = self.navigationController else {
            return nil
        }

        guard let viewControllers = self.navigationController?.viewControllers else {
            return nil
        }

        guard viewControllers.count >= 2 else {
            return nil
        }        
        return viewControllers[viewControllers.count - 2]
    }
}

для swift 3 вы можете сделать это:

var backtoViewController:UIViewController!
for viewController in (self.navigationController?.viewControllers)!.reversed() {
    if viewController is NameOfMyDestinationViewController {
            backtoViewController = viewController
    }
}
self.navigationController!.popToViewController(backtoViewController, animated: true)

Вам нужно только заменить "NameOfMyDestinationViewController" на viewController, который вы хотите вернуть.

Реализация для Swift 2.2 - добавьте это в UIViewController расширение. Сейф в том смысле, что он вернется nil если viewcontroller является rootvc или нет в навигационном контроллере.

var previousViewController: UIViewController? {
  guard let viewControllers = navigationController?.viewControllers else {
    return nil
  }
  var previous: UIViewController?
  for vc in viewControllers{
    if vc == self {
      break
    }
    previous = vc
  }
  return previous
}

Мое расширение, Свифт 3

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let controllers = navigationController?.viewControllers, controllers.count > 1 else { return nil }
        switch controllers.count {
        case 2: return controllers.first
        default: return controllers.dropLast(2).first
        }
    }
}
Другие вопросы по тегам