Як ідентифікувати попередній контролер перегляду в стеку навігації


78

У мене 2 окремі navigationcontrollers, один з RootViewControllerА, а другий з RootViewControllerБ.

Я можу натиснути ViewControllerC на навігаційний стек A або B.

Питання: Коли я перебуваю в ViewControllerC, як я можу дізнатись, чи перебуваю я в стосі, що належить A або B?


7
Чому б просто не створити попередню властивістьViewController на C, яку ви встановили, коли натискаєте C? Або надати C необхідну інформацію від A або B, коли ви натискаєте на неї?
Terry Wilcox

1
@TerryWilcox, тому що сьогодні відносини можуть бути дуже складними
Вячеслав

Відповіді:


107

Ви можете використовувати властивість UINavigationController' viewControllers:

@property(nonatomic, copy) NSArray *viewControllers

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

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

Ви можете використати це, щоб перевірити, чи є кореневий контролер подання (той, що має індекс масиву 0) контролером перегляду A або B.


Як я можу отримати це як рядок у SWIFT .. (я новачок у швидкій роботі)
M_R_K

@cyberboy так само просто: зvar viewControllers: [UIViewController]
NerdyTherapist

1
Попередній контролер перегляду буде оviewControllers.last
Бурак

@Burak viewControllers.lastмає поточний контролер перегляду, для того, щоб отримати попередній контролер перегляду, слід використовуватиviewControllers[viewControllers.count-2]
Ganpat

102

Ось реалізація прийнятої відповіді:

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

    if (numberOfViewControllers < 2)
        return nil;
    else
        return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}

20
Я рекомендую додати це як категорію наUIViewController
MaxGabriel

28
- (UIViewController *)backViewController
{
    NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];

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

11

Більш загальна реалізація прийнятої відповіді:

- (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;
}

Це поверне правильний "контролер перегляду ззаду" незалежно від того, де поточний клас знаходиться в стеці навігації.


9

Швидка реалізація 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
    }
}

Я опублікував модифіковану версію цього коду, яка має підтримку Swift 3 нижче, як нову відповідь.
Cin316

9

Ось модифікована версія коду Swift Prabhu Beeman, який адаптує його для підтримки 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
    }
}

пара приміток: reverse () тепер перевернуто (), а self.navigationController? .viewControllers ніколи не містить контролера перегляду "self", тому повернути stack.last має бути достатньо
Kappe

3

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

Отримавши цей екземпляр, ви можете перевірити його тип, записавши, що виходить із NSStringFromClass()функції. Або ви можете зберегти деякий static constрядок ідентифікатора в контролерах A і B, а також функцію отримання, яка виводить рядок.


будь-який простий спосіб отримання поточного індексу контролера перегляду або я повинен їх жорстко кодувати залежно від моєї структури ієрархії.
HpTerm

3

Як UINavigationControllerпродовження:

extension UINavigationController {

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

}

2

Швидка реалізація коду @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
    }

Як я можу отримати це у вигляді рядка .. (Я новачок у швидкій роботі)
M_R_K

@cyberboy Привіт! Я не впевнений, що розумію ваше запитання. Ви хочете отримати опис backViewController як рядок? Якщо так, ви можете подумати println("backViewController is: \(backViewController.description)"); це дасть вам такий опис, як "UINavigationController: 0x7fcea1d286b0", який не дуже зрозумілий, але принаймні дозволяє ідентифікувати об'єкт. Як я вже сказав, я не впевнений, що саме вам потрібно ...
cdf1982

1

Використовуйте navigationControllerметод, щоб отримати його. Дивіться документацію на сайті Apple .

navigationController Батько або предок, який є контролером навігації. (лише для читання)

@property (неатомний, лише для читання, зберегти) UINavigationController * navigationController

Обговорення повертає контролер навігації, лише якщо контролер перегляду знаходиться у своєму стеку. Ця властивість рівна нулю, якщо не вдається знайти навігаційний контролер.

Доступність Доступно в iOS 2.0 та новіших версіях.


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];
}

1

Більш стислий імпульс Свіфта:

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]
    }
}

0

Знайти попередній контролер перегляду просто.

У вашому випадку, тобто ви перебуваєте в C, і вам потрібна B, [self.navigationController.viewControllers lastObject]- це те, що ви хочете.

Для A, оскільки A - це кореневий контролер подання, ви можете просто замінити lastObjectна, firstObjectщоб отримати.


0

Реалізація для Swift 2.2 - додайте це у UIViewControllerрозширення. Безпечний в тому сенсі, що він повернеться, nilякщо контролер перегляду є 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
}

0

З Свіфтом за допомогою охоронця.

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]
    }
}

0

Моє розширення, швидко 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
        }
    }
}

0

для 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, який ви хочете повернути.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.