So identifizieren Sie den vorherigen Ansichts-Controller im Navigationsstapel


78

Ich habe 2 separate navigationcontrollers, eine mit RootViewControllerA und die andere mit RootViewControllerB.

Ich kann ViewControllerC entweder auf den Navigationsstapel von A oder B schieben .

Frage: Wenn ich in ViewControllerC bin , wie kann ich herausfinden, ob ich in dem Stapel bin, der zu A oder B gehört?


7
Warum nicht einfach eine vorherige ViewController-Eigenschaft für C erstellen, die Sie beim Drücken von C festlegen? Oder geben Sie C die Informationen, die es von A oder B benötigt, wenn Sie es drücken?
Terry Wilcox

1
@ TerryWilcox, weil die Beziehungen heutzutage sehr kompliziert sein könnten
Vyacheslav

Antworten:


107

Sie könnten die Verwendung UINavigationControllers‘ viewControllersEigenschaft:

@property(nonatomic, copy) NSArray *viewControllers

Diskussion: Der Root-View-Controller befindet sich im Array auf Index 0, der Back-View-Controller auf Index n-2 und der Top-Controller auf Index n-1, wobei n die Anzahl der Elemente im Array ist.

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

Sie können dies verwenden, um zu testen, ob der Root-View-Controller (der am Array-Index 0) View-Controller A oder B ist.


Wie kann ich das als String in SWIFT bekommen
?

@cyberboy genauso einfach: mitvar viewControllers: [UIViewController]
NerdyTherapist

1
Vorherige Ansicht Controller wird beiviewControllers.last
Burak

@ Burak viewControllers.lasthat aktuelle Ansicht Controller, Um vorherige Ansicht Controller zu erhalten, sollte man verwendenviewControllers[viewControllers.count-2]
Ganpat

102

Hier ist die Implementierung der akzeptierten Antwort:

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

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

20
Ich empfehle dies als Kategorie hinzuzufügen amUIViewController
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

Eine allgemeinere Umsetzung der akzeptierten Antwort:

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

Dies gibt den korrekten "Back View Controller" zurück, unabhängig davon, wo sich die aktuelle Klasse auf dem Navigationsstapel befindet.


9

Schnelle Implementierung von tjklemz- Code als Erweiterung:

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

Ich habe eine modifizierte Version dieses Codes veröffentlicht, die unten Swift 3-Unterstützung als neue Antwort bietet.
Cin316

9

Hier ist eine modifizierte Version von Prabhu Beemans Swift-Code, die ihn an die Unterstützung von Swift 3 anpasst:

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

Ein paar Anmerkungen: reverse () ist jetzt umgekehrt () und der self.navigationController? .viewControllers enthält niemals den "self" -Ansichts-Controller, daher sollte die Rückgabe von stack.last ausreichen
Kappe

3

Greifen Sie auf das n-2Element der viewControllersEigenschaft zu, um auf den übergeordneten Ansichtscontroller zuzugreifen.

Sobald Sie diese Instanz haben, können Sie ihren Typ überprüfen, indem Sie protokollieren, was aus der NSStringFromClass()Funktion herauskommt . Oder Sie können eine static constBezeichnerzeichenfolge in den Controllern A und B und eine Getter-Funktion behalten , die die Zeichenfolge druckt.


eine einfache Möglichkeit, den aktuellen Index eines View Controllers abzurufen, oder ich soll sie abhängig von meiner Hierarchiestruktur fest codieren.
HpTerm

3

Als UINavigationControllerErweiterung:

extension UINavigationController {

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

}

2

Schnelle Implementierung von @ tjklemz-Code:

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
    }

Wie kann ich das als String bekommen
?

@cyberboy Hallo! Ich bin mir nicht sicher, ob ich deine Frage verstehe. Möchten Sie die Beschreibung von backViewController als String erhalten? Wenn ja, könnten Sie in Betracht ziehen println("backViewController is: \(backViewController.description)"); Dadurch erhalten Sie eine Beschreibung wie "UINavigationController: 0x7fcea1d286b0", die nicht sehr klar ist, aber zumindest die Identifizierung des Objekts ermöglicht. Wie gesagt, ich bin mir nicht sicher, was Sie genau brauchen ...
cdf1982

1

Verwenden Sie die navigationControllerMethode, um es abzurufen. Siehe Dokumentation auf der Apple-Website .

navigationController Ein Elternteil oder Vorfahr, der ein Navigationscontroller ist. (schreibgeschützt)

@property (nichtatomar, schreibgeschützt, beibehalten) UINavigationController * navigationController

Diskussion Gibt einen Navigationscontroller nur zurück, wenn sich der Ansichtscontroller in seinem Stapel befindet. Diese Eigenschaft ist gleich Null, wenn ein Navigationscontroller nicht gefunden werden kann.

Verfügbarkeit Verfügbar in iOS 2.0 und höher.


1

Weil tote Pferde gerne geschlagen werden :)

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

Eine prägnantere schnelle Umsetzung:

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

Das Auffinden des vorherigen Ansichtscontrollers ist einfach.

In Ihrem Fall, dh Sie sind in C und Sie brauchen B, [self.navigationController.viewControllers lastObject]ist das , was Sie wollen.

Für A, da A der Wurzel - View - Controller ist, können Sie einfach ersetzen lastObjectmit firstObjectzu erhalten.


0

Implementierung für Swift 2.2 - Fügen Sie dies in eine UIViewControllerErweiterung ein. Sicher in dem Sinne, dass es zurückgegeben wird, nilwenn der Viewcontroller der Rootvc ist oder nicht in einem Navigationscontroller.

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

Mit Swift mit Wache.

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

Meine Erweiterung, schnell 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

Für Swift 3 können Sie dies tun:

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

Sie müssen nur "NameOfMyDestinationViewController" durch viewController ersetzen, den Sie zurückgeben möchten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.