À quoi servent les séquences Unwind et comment les utilisez-vous?

584

iOS 6 et Xcode 4.5 ont une nouvelle fonctionnalité appelée "Unwind Segue":

Les séquences de déroulement peuvent permettre la transition vers des instances existantes de scènes dans un storyboard

En plus de cette brève entrée dans les notes de publication de Xcode 4.5, UIViewController semble maintenant avoir quelques nouvelles méthodes:

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

Comment fonctionnent les séquences de déroulement et à quoi peuvent-elles servir?

Imre Kelényi
la source

Réponses:

1267

En un mot

Une séquence de déroulement (parfois appelée sortie de séquence ) peut être utilisé pour revenir naviguer par poussée, des enchaînements modales ou popover (comme si vous sauté l'élément de navigation dans la barre de navigation, fermé le popover ou de rejeter le contrôleur de vue présenté modalement). En plus de cela, vous pouvez réellement vous détendre non seulement dans une, mais dans une série de séquences push / modal / popover, par exemple "revenir en arrière" plusieurs étapes dans votre hiérarchie de navigation avec une seule action de déroulement.

Lorsque vous effectuez une séquence de déroulement, vous devez spécifier une action, qui est une méthode d'action du contrôleur de vue vers lequel vous souhaitez vous détendre.

Objectif c:

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

Rapide:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}

Le nom de cette méthode d'action est utilisé lorsque vous créez la séquence de déroulement dans le storyboard. De plus, cette méthode est appelée juste avant la séquence de déroulement. Vous pouvez obtenir le contrôleur de vue source à partir du UIStoryboardSegueparamètre passé pour interagir avec le contrôleur de vue qui a initié la transition (par exemple pour obtenir les valeurs de propriété d'un contrôleur de vue modal). À cet égard, la méthode a une fonction similaire à la prepareForSegue:méthode deUIViewController .

Mise à jour iOS 8: les séquences de déroulement fonctionnent également avec les séquences adaptatives d'iOS 8, telles que Afficher et Afficher les détails .

Un exemple

Ayons un storyboard avec un contrôleur de navigation et trois contrôleurs de vue enfant:

entrez la description de l'image ici

De Green View Controller, vous pouvez vous détendre (revenir en arrière) à Red View Controller. Du bleu, vous pouvez vous détendre au vert ou au rouge via le vert. Pour activer le déroulement, vous devez ajouter les méthodes d'action spéciales au rouge et au vert, par exemple voici la méthode d'action en rouge:

Objectif c:

@implementation RedViewController

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

@end

Rapide:

@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}

Une fois la méthode d'action ajoutée, vous pouvez définir la séquence de déroulement dans le storyboard en faisant glisser la souris sur l'icône Quitter. Ici, nous voulons nous détendre du rouge au vert lorsque le bouton est enfoncé:

entrez la description de l'image ici

Vous devez sélectionner l'action définie dans le contrôleur de vue vers lequel vous souhaitez vous détendre:

entrez la description de l'image ici

Vous pouvez également vous détendre en passant du rouge au bleu (qui est "à deux pas" de la pile de navigation). La clé consiste à sélectionner l'action de déroulement correcte.

Avant d'effectuer la séquence de déroulement, la méthode d'action est appelée. Dans l'exemple, j'ai défini une séquence de déroulement vers le rouge à partir du vert et du bleu. Nous pouvons accéder à la source du déroulement dans la méthode d'action via le paramètre UIStoryboardSegue:

Objectif 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!");
    }
}

Rapide:

@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")
    }
}

Le déroulement fonctionne également grâce à une combinaison de séquences push / modales. Par exemple, si j'ajoutais un autre contrôleur de vue jaune avec une séquence modale, nous pourrions passer du jaune au rouge en une seule étape:

entrez la description de l'image ici

Se détendre du code

Lorsque vous définissez une séquence de déroulement en faisant glisser quelque chose vers le symbole Quitter d'un contrôleur de vue, une nouvelle séquence apparaît dans l'aperçu du document:

entrez la description de l'image ici

La sélection de la séquence et l'accès à l'inspecteur d'attributs révèlent la propriété "Identifier". Utilisez ceci pour donner un identifiant unique à votre enchaînement:

entrez la description de l'image ici

Après cela, la séquence de déroulement peut être effectuée à partir du code comme n'importe quelle autre séquence:

Objectif c:

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

Rapide:

performSegueWithIdentifier("UnwindToRedSegueID", sender: self)
Imre Kelényi
la source
12
+1 bonne réponse. Ils sonnent vraiment bien, mais les méthodes ne peuvent-elles pas ressembler dismissViewControllerAnimated:completion:ou popViewControllerAnimated:réaliser la même chose?
Sam Spencer
32
Bien sûr qu'ils le peuvent. Cependant, si vous utilisez des storyboards, les séquences de déroulement peuvent souvent réaliser la même chose avec beaucoup moins de code. En fait, vous pouvez maintenant ignorer un contrôleur de vue présenté de façon modale sans écrire de code. Bien sûr, il existe encore de nombreux cas où la fermeture des contrôleurs du code est la bonne chose à faire.
Imre Kelényi
7
Assurez-vous d'ajouter votre méthode d'action à votre fichier d'en-tête, sinon Storyboard ne sera pas au courant.
Kyle C
17
Un autre avantage par rapport à dismissViewControllerAnimated:completion:ou popViewControllerAnimated:est que la méthode que vous avez ajoutée au contrôleur de vue auquel vous vous déroulez est appelée et que vous avez ainsi un moyen simple de savoir que le contrôleur de vue présenté est terminé sans avoir à faire du contrôleur de vue présenté un délégué du contrôleur de vue présenté. .
honus
8
Puis-je suggérer une légère modification? Il n'était pas "évidemment" clair que vous mettiez - (IBAction) unwindTRed: (UIStoryboardSegue *) unwindSegue dans le RedViewController.m, et à son tour, cela est universellement disponible dans "n'importe lequel" des boutons de sortie verts pour n'importe quel story-board. Fantastique réponse et maintenant je vais l'utiliser pour d'autres problèmes. Merci!
John Ballinger
166

En ce qui concerne l'utilisation des séquences de déroulement dans StoryBoard ...

Étape 1)

Accédez au code du contrôleur de vue auquel vous souhaitez vous détendre et ajoutez ceci:

Objectif c

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

Assurez-vous également de déclarer cette méthode dans votre fichier .h dans Obj-C

Rapide

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

Étape 2)

Dans le storyboard, accédez à la vue à partir de laquelle vous souhaitez vous détendre et faites simplement glisser une séquence depuis votre bouton ou quoi que ce soit jusqu'à la petite icône orange "QUITTER" en haut à droite de votre vue source.

entrez la description de l'image ici

Il devrait maintenant y avoir une option pour se connecter à "- unwindToViewControllerNameHere"

Voilà, votre enchaînement se déroulera lorsque votre bouton sera appuyé.

Travis M.
la source
5
J'ai constaté qu'avec Xcode 4.5 et versions antérieures, il était nécessaire de déclarer l'IBAction dans l'en-tête. Je ne sais pas si c'est toujours vrai.
Steven Fisher
2
Existe-t-il un moyen de faire l'étape 2 sans storyboard, c'est-à-dire par programme? Mon storyboard (constructeur d'interface) est foiré et il n'affiche pas les séquences de déroulement (bogue xcode).
Van Du Tran
46

Les séquences de déroulement sont utilisées pour "revenir" à un contrôleur de vue à partir duquel, à travers un certain nombre de séquences, vous êtes arrivé au contrôleur de vue "actuel".

Imaginez que vous ayez quelque chose MyNavControlleravec Acomme contrôleur de vue racine. Maintenant, vous utilisez une séquence push pour B. Maintenant, le contrôleur de navigation a A et B dans son viewControllerstableau, et B est visible. Maintenant, vous présentezC modale.

Avec les séquences de déroulement, vous pouvez désormais vous détendre "en arrière" de (c'est- Cà B-dire en supprimant le contrôleur de vue présenté de façon modale), "annulant" essentiellement la séquence modale. Vous pouvez même vous détendre jusqu'au contrôleur de vue racine A, annulant à la fois la séquence modale et la séquence de poussée.

Les séquences de déroulement facilitent le retour en arrière. Par exemple, avant iOS 6, la meilleure pratique pour rejeter les contrôleurs de vue présentés était de définir le contrôleur de vue présenté comme délégué du contrôleur de vue présenté, puis d'appeler votre méthode de délégué personnalisée, qui rejette ensuite leViewViewController . Cela vous semble lourd et compliqué? C'était. C'est pourquoi les séquences de déroulement sont agréables.

Yang Meyer
la source
7
Vous pouvez appeler à dismissViewController:animatedpartir du contrôleur présenté. Vous n'êtes pas obligé de déléguer cela. Bien sûr, si vous devez renvoyer des données, vous avez besoin d'une délégation ou d'une autre méthode.
mxcl
3
Bien que vous puissiez appeler à dismissViewController:animated:partir du contrôleur présenté, la "meilleure pratique" était en effet d'appeler une méthode déléguée sur le contrôleur présentant pour le faire pour vous, comme l'a mentionné Yang.
Chris Nolet
36

Quelque chose que je n'ai pas vu mentionné dans les autres réponses ici, c'est comment vous vous débrouillez lorsque vous ne savez pas d'où vient la séquence initiale, ce qui pour moi est un cas d'utilisation encore plus important. Par exemple, supposons que vous disposez d'un contrôleur de vue d'aide ( H ) que vous affichez de manière modale à partir de deux contrôleurs de vue différents ( A et B ):

AH
BH

Comment configurez-vous la séquence de déroulement pour revenir au contrôleur de vue correct? La réponse est que vous déclarez une action de déroulement en A et B avec le même nom , par exemple:

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

De cette façon, le déroulement trouvera le contrôleur de vue ( A ou B ) qui a initié la séquence et y reviendra.

En d' autres termes, penser à l'action dérouleur comme décrivant où le Segue vient de , plutôt que là où il va.

shawkinaw
la source
2
Merci pour cette info, je cherchais ça.
Madhu
2
c'est vraiment super de mentionner cette information car j'ai déjà implémenté la solution et rien ne se passe jusqu'à ce que j'obtienne votre conseil ici merci beaucoup pour votre soutien
Amr Angry
Ceci est une grande info! Merci beaucoup!
Dominique Vial
24

Swift iOS:

Étape 1: définissez cette méthode dans la vue de votre contrôleur MASTER. dans lequel vous souhaitez revenir:

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

    println("Called goToSideMenu: unwind action")

}

Étape 2: (StoryBoard) Faites un clic droit sur votre bouton SLAVE / CHILD EXIT et sélectionnez "goToSideMenu" comme action pour vous connecter Bouton sur lequel vous cliquez pour revenir à votre vue de contrôleur MASTER:

entrez la description de l'image ici étape 3: construire et exécuter ...

Vinod Joshi
la source
1

Par exemple, si vous naviguez de viewControllerB vers viewControllerA, dans votre viewControllerA ci-dessous, le délégué appellera et les données seront partagées.

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

}
  • Détendez le contrôleur Seague Source View (vous devez connecter le bouton de sortie à l'icône de sortie de VC et le connecter à unwindseague:

entrez la description de l'image ici

  • Unwind Seague Completed -> TextLabel of viewControllerA is Changed.

entrez la description de l'image ici

Technologie
la source