Wofür sind Unwind-Segmente und wie verwenden Sie sie?

584

iOS 6 und Xcode 4.5 verfügen über eine neue Funktion, die als "Unwind Segue" bezeichnet wird:

Abwicklungssegmente können den Übergang zu vorhandenen Instanzen von Szenen in einem Storyboard ermöglichen

Zusätzlich zu diesem kurzen Eintrag in den Versionshinweisen von Xcode 4.5 scheint UIViewController nun einige neue Methoden zu haben:

- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier

Wie funktionieren Abwicklungssegues und wofür können sie verwendet werden?

Imre Kelényi
quelle

Antworten:

1267

In einer Nussschale

Ein Abwicklungs-Segue (manchmal auch als Exit-Segue bezeichnet ) kann verwendet werden, um durch Push-, Modal- oder Popover-Segues zurück zu navigieren (als hätten Sie das Navigationselement aus der Navigationsleiste entfernt, das Popover geschlossen oder den modal dargestellten Ansichts-Controller geschlossen). Darüber hinaus können Sie nicht nur eine, sondern eine Reihe von Push- / Modal- / Popover-Abschnitten abwickeln, z. B. mehrere Schritte in Ihrer Navigationshierarchie mit einer einzigen Abwicklungsaktion "zurückgehen".

Wenn Sie einen Abwicklungsabschnitt ausführen, müssen Sie eine Aktion angeben, bei der es sich um eine Aktionsmethode des Ansichtscontrollers handelt, zu dem Sie sich abwickeln möchten.

Ziel c:

- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
}

Schnell:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}

Der Name dieser Aktionsmethode wird verwendet, wenn Sie den Abwicklungsbereich im Storyboard erstellen. Darüber hinaus wird diese Methode unmittelbar vor dem Abwickeln aufgerufen. Sie können den Quellansichts-Controller über den übergebenen UIStoryboardSegueParameter dazu bringen, mit dem Ansichts-Controller zu interagieren, der den Übergang initiiert hat (z. B. um die Eigenschaftswerte eines modalen Ansichts-Controllers abzurufen). In dieser Hinsicht hat das Verfahren eine ähnliche Funktion wie das prepareForSegue:Verfahren von UIViewController.

iOS 8-Update: Abwicklungssegues funktionieren auch mit den adaptiven Segues von iOS 8 wie Show und Show Detail .

Ein Beispiel

Lassen Sie uns ein Storyboard mit einem Navigationscontroller und drei untergeordneten Ansichtscontrollern erstellen:

Geben Sie hier die Bildbeschreibung ein

Vom Green View Controller können Sie sich entspannen (zurück navigieren) zum Red View Controller. Von Blau können Sie sich über Grün nach Grün oder Rot entspannen. Um das Abwickeln zu aktivieren, müssen Sie Rot und Grün die speziellen Aktionsmethoden hinzufügen. Beispiel: Hier ist die Aktionsmethode in Rot:

Ziel c:

@implementation RedViewController

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
}

@end

Schnell:

@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}

Nachdem die Aktionsmethode hinzugefügt wurde, können Sie den Abwicklungsbereich im Storyboard definieren, indem Sie bei gedrückter Ctrl-Taste auf das Symbol Beenden ziehen. Hier wollen wir uns von Grün zu Rot entspannen, wenn die Taste gedrückt wird:

Geben Sie hier die Bildbeschreibung ein

Sie müssen die Aktion auswählen, die im Ansichts-Controller definiert ist, zu dem Sie sich abwickeln möchten:

Geben Sie hier die Bildbeschreibung ein

Sie können sich auch von Blau zu Rot entspannen (das ist "zwei Schritte entfernt" im Navigationsstapel). Die Taste wählt die richtige Abwickelaktion aus.

Bevor der Abwicklungsabschnitt ausgeführt wird, wird die Aktionsmethode aufgerufen. Im Beispiel habe ich einen Abwicklungsbereich von Grün und Blau zu Rot definiert. Über den Parameter UIStoryboardSegue können wir in der Aktionsmethode auf die Quelle des Abwickelns zugreifen:

Ziel c:

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
    UIViewController* sourceViewController = unwindSegue.sourceViewController;

    if ([sourceViewController isKindOfClass:[BlueViewController class]])
    {
        NSLog(@"Coming from BLUE!");
    }
    else if ([sourceViewController isKindOfClass:[GreenViewController class]])
    {
        NSLog(@"Coming from GREEN!");
    }
}

Schnell:

@IBAction func unwindToRed(unwindSegue: UIStoryboardSegue) {
    if let blueViewController = unwindSegue.sourceViewController as? BlueViewController {
        println("Coming from BLUE")
    }
    else if let redViewController = unwindSegue.sourceViewController as? RedViewController {
        println("Coming from RED")
    }
}

Das Abwickeln funktioniert auch durch eine Kombination von Push- / Modal-Segues. Wenn ich beispielsweise einen weiteren Controller für die gelbe Ansicht mit einem modalen Übergang hinzufügen würde, könnten wir uns in einem einzigen Schritt von Gelb bis zurück zu Rot entspannen:

Geben Sie hier die Bildbeschreibung ein

Abwickeln vom Code

Wenn Sie einen Abwicklungsabschnitt definieren, indem Sie bei gedrückter Ctrl-Taste etwas auf das Exit-Symbol eines Ansichts-Controllers ziehen, wird in der Dokumentübersicht ein neuer Abschnitt angezeigt:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie den Abschnitt auswählen und zum Attributinspektor wechseln, wird die Eigenschaft "Bezeichner" angezeigt. Verwenden Sie diese Option, um Ihrem Segue eine eindeutige Kennung zu geben:

Geben Sie hier die Bildbeschreibung ein

Danach kann der Abwicklungs-Segue wie jeder andere Segue aus dem Code ausgeführt werden:

Ziel c:

[self performSegueWithIdentifier:@"UnwindToRedSegueID" sender:self];

Schnell:

performSegueWithIdentifier("UnwindToRedSegueID", sender: self)
Imre Kelényi
quelle
12
+1 tolle Antwort. Sie klingen wirklich gut, aber können Methoden nicht dasselbe mögen dismissViewControllerAnimated:completion:oder popViewControllerAnimated:erreichen?
Sam Spencer
32
Sicher können sie. Wenn Sie jedoch Storyboards verwenden, können Abwicklungssegmente häufig dasselbe mit viel weniger Code erreichen. Tatsächlich können Sie jetzt einen modal dargestellten Ansichts-Controller schließen, ohne Code zu schreiben. Natürlich gibt es immer noch viele Fälle, in denen das Schließen von Controllern aus Code das Richtige ist.
Imre Kelényi
7
Stellen Sie sicher, dass Sie Ihre Aktionsmethode zu Ihrer Header-Datei hinzufügen, da Storyboard sonst nichts davon weiß.
Kyle C
17
Ein weiterer Vorteil gegenüber dismissViewControllerAnimated:completion:oder popViewControllerAnimated:besteht darin, dass die Methode, die Sie dem View Controller hinzugefügt haben, zu dem Sie sich abwickeln, aufgerufen wird, sodass Sie auf einfache Weise feststellen können, dass der präsentierte View Controller fertig ist, ohne den präsentierenden View Controller zu einem Delegaten des präsentierten View Controllers machen zu müssen .
Honus
8
Könnte ich eine leichte Bearbeitung vorschlagen? Es war nicht "offensichtlich" klar, dass Sie - (IBAction) unwindTRed: (UIStoryboardSegue *) unwindSegue in RedViewController.m eingefügt haben, und dies ist wiederum allgemein in "jeder" der grünen Exit-Schaltflächen für jedes Storyboard verfügbar. Fantastische Antwort und jetzt werde ich dies für andere Fragen verwenden. Vielen Dank!
John Ballinger
166

Was die Verwendung von Abwicklungssegmenten in StoryBoard angeht ...

Schritt 1)

Wechseln Sie zu dem Code für den Ansichts-Controller, zu dem Sie sich entspannen möchten , und fügen Sie diesen hinzu:

Ziel c

- (IBAction)unwindToViewControllerNameHere:(UIStoryboardSegue *)segue {
    //nothing goes here
}

Stellen Sie sicher, dass Sie diese Methode auch in Ihrer .h-Datei in Obj-C deklarieren

Schnell

@IBAction func unwindToViewControllerNameHere(segue: UIStoryboardSegue) {
    //nothing goes here
}

Schritt 2)

Wechseln Sie im Storyboard zu der Ansicht, aus der Sie sich entspannen möchten, und ziehen Sie einfach einen Abschnitt von Ihrer Schaltfläche oder was auch immer bis zum kleinen orangefarbenen "EXIT" -Symbol oben rechts in Ihrer Quellansicht.

Geben Sie hier die Bildbeschreibung ein

Es sollte jetzt eine Option zum Herstellen einer Verbindung mit "- unwindToViewControllerNameHere" geben.

Das war's, Ihr Segue wird sich entspannen, wenn Sie auf Ihre Schaltfläche tippen.

Travis M.
quelle
5
Ich habe festgestellt, dass es mit Xcode 4.5 und früher notwendig war, die IBAction im Header zu deklarieren. Ich weiß nicht, ob das noch stimmt.
Steven Fisher
2
Gibt es eine Möglichkeit, Schritt 2 ohne Storyboard auszuführen, dh programmgesteuert? Mein Storyboard (Interface Builder) ist durcheinander und zeigt die Abwicklungssegmente nicht an (Xcode-Fehler).
Van Du Tran
46

Abwicklungssegmente werden verwendet, um zu einem Ansichts-Controller "zurückzukehren", von dem aus Sie über eine Reihe von Segmenten zum "aktuellen" Ansichts-Controller gelangen.

Stellen Sie sich vor, Sie haben etwas MyNavControllermit Aals Root-View-Controller. Jetzt verwenden Sie einen Push-Übergang zu B. Jetzt hat der Navigationscontroller A und B in seinem viewControllersArray und B ist sichtbar. Jetzt präsentieren Sie Cmodal.

Mit Abwicklungssegmenten können Sie jetzt "zurück" von Cbis Babwickeln (dh den modal dargestellten Ansichtscontroller schließen) und im Grunde das modale Segue "rückgängig machen". Sie können sich sogar bis zum Root-View-Controller Azurückziehen und sowohl den Modal-Segue als auch den Push-Segue rückgängig machen.

Abwickeln von Segues erleichtern das Zurückverfolgen. Vor iOS 6 bestand die beste Vorgehensweise zum Schließen von Controllern für präsentierte Ansichten beispielsweise darin , den Controller für präsentierte Ansichten als Delegaten für präsentierte View-Controller festzulegen und dann Ihre benutzerdefinierte Delegatenmethode aufzurufen, die dann den präsentierten ViewController schließt . Klingt umständlich und kompliziert? Es war. Deshalb sind Abwicklungsbereiche schön.

Yang Meyer
quelle
7
Sie können dismissViewController:animatedvom vorgestellten Controller aus anrufen . Das müssen Sie nicht delegieren. Wenn Sie Daten zurückgeben müssen, benötigen Sie natürlich eine Delegierung oder eine andere Methode.
mxcl
3
Während Sie dismissViewController:animated:vom präsentierten Controller aus anrufen können , bestand "Best Practice" darin, eine Delegatmethode auf dem präsentierenden Controller aufzurufen, um dies für Sie zu tun, wie Yang erwähnte.
Chris Nolet
36

Etwas, das ich in den anderen Antworten hier nicht erwähnt habe, ist, wie Sie mit dem Abwickeln umgehen, wenn Sie nicht wissen, woher der anfängliche Übergang stammt, was für mich ein noch wichtigerer Anwendungsfall ist. Angenommen, Sie haben einen Hilfeansichts-Controller ( H ), den Sie modal von zwei verschiedenen Ansichts-Controllern ( A und B ) anzeigen :

AH
BH.

Wie richten Sie den Abwicklungsbereich ein, damit Sie zum richtigen Ansichts-Controller zurückkehren? Die Antwort ist, dass Sie in A und B eine Abwicklungsaktion mit demselben Namen deklarieren , z.

// put in AViewController.swift and BViewController.swift
@IBAction func unwindFromHelp(sender: UIStoryboardSegue) {
    // empty
}

Auf diese Weise findet die Abwicklung den View Controller ( A oder B ), der den Übergang initiiert hat, und kehrt zu ihm zurück.

Mit anderen Worten, man denke an die Abroll Aktion wie beschreiben , wo der Übergang kommt aus , nicht dort , wo es geht.

shawkinaw
quelle
2
Danke für diese Info, ich habe danach gesucht.
Madhu
2
Es ist wirklich toll, diese Informationen zu erwähnen, da ich die Lösung bereits implementiert habe und nichts passiert, bis ich Ihren Tipp hier bekomme. Vielen Dank für Ihre Unterstützung
Amr Angry
Dies ist eine großartige Information! Vielen Dank!
Dominique Vial
24

Schnelles iOS:

Schritt 1: Definieren Sie diese Methode in Ihrer MASTER-Controller-Ansicht. in dem du zurückgehen willst:

//pragma mark - Unwind Seques
@IBAction func goToSideMenu(segue: UIStoryboardSegue) {

    println("Called goToSideMenu: unwind action")

}

Schritt 2: (StoryBoard) Klicken Sie mit der rechten Maustaste auf die Schaltfläche SLAVE / CHILD EXIT und wählen Sie "goToSideMenu" als Aktion, um Sie zu verbinden. Klicken Sie auf diese Schaltfläche, um zur MASTER-Controller-Ansicht zurückzukehren:

Geben Sie hier die Bildbeschreibung ein Schritt 3: Erstellen und ausführen ...

Vinod Joshi
quelle
1

Wenn Sie beispielsweise von viewControllerB zu viewControllerA navigieren, ruft der Delegat in Ihrem viewControllerA unten an und die Daten werden gemeinsam genutzt.

@IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
        if sender.source is ViewControllerB  {
            if let _ = sender.source as? ViewControllerB {
                self.textLabel.text = "Came from B = B->A , B exited"
            }
            
        }

}
  • Seague Source View Controller abwickeln (Sie müssen die Exit-Taste mit dem Exit-Symbol von VC verbinden und mit dem Abwicklungs-League verbinden:

Geben Sie hier die Bildbeschreibung ein

  • Seague abgeschlossen abgeschlossen -> TextLabel von viewControllerA wurde geändert.

Geben Sie hier die Bildbeschreibung ein

Technik
quelle