¿Para qué sirven los segmentos de Unwind y cómo los usas?

584

iOS 6 y Xcode 4.5 tienen una nueva característica denominada "Unwind Segue":

Los segmentos de desconexión pueden permitir la transición a instancias existentes de escenas en un guión gráfico

Además de esta breve entrada en las notas de la versión de Xcode 4.5, UIViewController ahora parece tener un par de métodos nuevos:

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

¿Cómo funcionan los segmentos de desconexión y para qué se pueden usar?

Imre Kelényi
fuente

Respuestas:

1267

En una palabra

Se puede usar un segue de desenrollado (a veces llamado segue de salida ) para navegar hacia atrás a través de segues push, modal o popover (como si sacara el elemento de navegación de la barra de navegación, cerró el popover o descartó el controlador de vista presentado modalmente). Además de eso, puede desenvolverse no solo a través de una serie de segmentos push / modal / popover, por ejemplo, "retroceder" múltiples pasos en su jerarquía de navegación con una sola acción de desenrollado.

Cuando realiza una secuencia de desenrollado, debe especificar una acción, que es un método de acción del controlador de vista al que desea desenrollarse.

C objetivo:

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

Rápido:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}

El nombre de este método de acción se usa cuando crea la secuencia de desenrollado en el guión gráfico. Además, este método se llama justo antes de que se realice la secuencia de desenrollado. Puede obtener el controlador de vista de origen del UIStoryboardSegueparámetro pasado para interactuar con el controlador de vista que inició la segue (por ejemplo, para obtener los valores de propiedad de un controlador de vista modal). A este respecto, el método tiene una función similar al prepareForSegue:método de UIViewController.

Actualización de iOS 8: Unwind segues también funciona con los segmentos adaptativos de iOS 8, como Show y Show Detail .

Un ejemplo

Tengamos un guión gráfico con un controlador de navegación y tres controladores de vista secundarios:

ingrese la descripción de la imagen aquí

Desde Green View Controller puede relajarse (navegar hacia atrás) a Red View Controller. Desde azul puede relajarse en verde o en rojo a través de verde. Para habilitar el desenrollado, debe agregar los métodos de acción especiales a Rojo y Verde, por ejemplo, aquí está el método de acción en Rojo:

C objetivo:

@implementation RedViewController

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

@end

Rápido:

@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}

Una vez que se ha agregado el método de acción, puede definir la secuencia de desenrollado en el guión gráfico al arrastrar el control al icono Salir. Aquí queremos desconectarnos de Rojo a Verde cuando se presiona el botón:

ingrese la descripción de la imagen aquí

Debe seleccionar la acción que se define en el controlador de vista que desea desenrollar:

ingrese la descripción de la imagen aquí

También puede relajarse en Rojo desde Azul (que está "a dos pasos" en la pila de navegación). La clave es seleccionar la acción de desenrollado correcta.

Antes de que se realice la secuencia de desenrollado, se llama al método de acción. En el ejemplo, definí un desenrollar segue a Rojo desde Verde y Azul. Podemos acceder a la fuente del desenrollado en el método de acción a través del parámetro UIStoryboardSegue:

C objetivo:

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

Rápido:

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

Desenrollar también funciona a través de una combinación de segues push / modal. Por ejemplo, si agregué otro controlador de vista Amarillo con una secuencia modal, podríamos desconectarnos de Amarillo hasta el Rojo en un solo paso:

ingrese la descripción de la imagen aquí

Desenrollar del código

Cuando define un segue de desenrollado arrastrando algo con control al símbolo Exit de un controlador de vista, aparece un nuevo segue en el Esquema del documento:

ingrese la descripción de la imagen aquí

Al seleccionar el segmento e ir al Inspector de atributos, se revela la propiedad "Identificador". Use esto para dar un identificador único a su segue:

ingrese la descripción de la imagen aquí

Después de esto, el desenrollado puede realizarse desde el código como cualquier otro segue:

C objetivo:

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

Rápido:

performSegueWithIdentifier("UnwindToRedSegueID", sender: self)
Imre Kelényi
fuente
12
+1 gran respuesta. Suenan muy bien, pero ¿no pueden los métodos gustar dismissViewControllerAnimated:completion:o popViewControllerAnimated:lograr lo mismo?
Sam Spencer el
32
Claro que pueden. Sin embargo, si está utilizando guiones gráficos, los segmentos de desconexión a menudo pueden lograr lo mismo con mucho menos código. En realidad, ahora puede descartar un controlador de vista presentado modalmente sin escribir ningún código. Por supuesto, todavía hay muchos casos en los que cerrar los controladores desde el código es lo correcto.
Imre Kelényi
77
Asegúrese de agregar su método de acción a su archivo de encabezado o, de lo contrario, Storyboard no lo sabrá.
Kyle C
17
Otra ventaja sobre dismissViewControllerAnimated:completion:o popViewControllerAnimated:es que se llama al método que agregó al controlador de vista al que se está desenrollando y, por lo tanto, tiene una manera fácil de saber que el controlador de vista presentado está terminado sin tener que hacer que el controlador de vista actual sea un delegado del controlador de vista presentado .
honus
8
¿Puedo sugerir una pequeña edición? No estaba "obviamente" claro que pusiste - (IBAction) unwindTRed: (UIStoryboardSegue *) unwindSegue en RedViewController.m, y a su vez esto está universalmente disponible en "cualquiera" de los botones de salida verdes para cualquier storyboard. Fantástica respuesta y ahora usaré esto para otros problemas. ¡Gracias!
John Ballinger
166

En cuanto a cómo usar desconectar segues en StoryBoard ...

Paso 1)

Vaya al código del controlador de vista en el que desea relajarse y agregue esto:

C objetivo

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

Asegúrese de declarar también este método en su archivo .h en Obj-C

Rápido

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

Paso 2)

En el guión gráfico, vaya a la vista desde la que desea relajarse y simplemente arrastre un segmento desde su botón o lo que sea hasta el pequeño ícono naranja "SALIR" en la esquina superior derecha de su vista de origen.

ingrese la descripción de la imagen aquí

Ahora debería haber una opción para conectarse a "- unwindToViewControllerNameHere"

Eso es todo, tu segue se desenrollará cuando toques el botón.

Travis M.
fuente
55
He encontrado que con Xcode 4.5 y anteriores era necesario declarar el IBAction en el encabezado. No sé si esto sigue siendo cierto.
Steven Fisher
2
¿Hay alguna manera de hacer el Paso 2 sin guión gráfico, es decir, mediante programación? Mi storyboard (generador de interfaces) está en mal estado y no muestra los segmentos de desenrollado (error de xcode).
Van Du Tran
46

Los valores de desconexión se utilizan para "volver" a algún controlador de vista desde el cual, a través de una serie de valores, se obtiene el controlador de vista "actual".

Imagine que tiene algo MyNavControllercon Asu controlador de vista raíz. Ahora usa un empuje segue a B. Ahora el controlador de navegación tiene A y B en su viewControllersmatriz, y B es visible. Ahora presentasC modalmente.

Con segues de desenrollado, puede ahora relajarse "vuelta" de Ca B(es decir, se desestima el controlador de vista modal presenta), básicamente "deshacer" el segue modal. Incluso podría relajarse hasta el controlador de vista raíz A, deshaciendo tanto el modo modal como el segmento de inserción.

Relájese segues hacen que sea fácil retroceder. Por ejemplo, antes de iOS 6, la mejor práctica para descartar los controladores de vista presentados era establecer el controlador de vista de presentación como el delegado del controlador de vista presentada, luego llamar a su método de delegado personalizado, que luego descarta el Controlador de vista presentada . ¿Suena engorroso y complicado? Era. Es por eso que relajarse segues son agradables.

Yang Meyer
fuente
77
Puede llamar dismissViewController:animateddesde el controlador presentado. No tienes que delegar eso. Por supuesto, si necesita devolver datos, entonces necesita delegación u otro método.
mxcl
3
Si bien puede llamar dismissViewController:animated:desde el controlador presentado, la "mejor práctica" fue llamar a un método delegado en el controlador que presenta para que lo haga por usted, como mencionó Yang.
Chris Nolet
36

Algo que no vi mencionado en las otras respuestas aquí es cómo lidiar con el desenrollado cuando no sabe dónde se originó el segmento inicial, lo que para mí es un caso de uso aún más importante. Por ejemplo, supongamos que tiene un controlador de vista de ayuda ( H ) que muestra modalmente desde dos controladores de vista diferentes ( A y B ):

AH
BH

¿Cómo se configura la desconexión para que regrese al controlador de vista correcto? La respuesta es que declaras una acción de desconexión en A y B con el mismo nombre , por ejemplo:

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

De esta manera, el desenrollado encontrará el controlador de vista ( A o B ) que inició la secuencia y volverá a él.

En otras palabras, pensar en la acción de desenrollado como la descripción de donde el segue viene de , en lugar de hacia dónde se dirige a.

shawkinaw
fuente
2
Gracias por esta información, estaba buscando esto.
Madhu
2
es realmente genial mencionar esta información ya que ya estoy implementando la solución y no pasa nada hasta que recibo su consejo aquí muchas gracias por su apoyo
Amr Angry
Esta es una gran pieza de información! ¡Muchas gracias!
Dominique Vial
24

Swift iOS:

Paso 1: defina este método en la vista del controlador MASTER. en el que quieres volver:

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

    println("Called goToSideMenu: unwind action")

}

Paso 2: (StoryBoard) Haz clic derecho en tu botón ESCLAVO / SALIDA INFANTIL y selecciona "goToSideMenu" como acción para conectarte Botón en el que harás clic para volver a la vista del controlador MASTER:

ingrese la descripción de la imagen aquí Paso 3: compilar y ejecutar ...

Vinod Joshi
fuente
1

Por ejemplo, si navega desde viewControllerB hasta viewControllerA, en su viewControllerA debajo, el delegado llamará y los datos se compartirán.

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

}
  • Desenrolle Seague Source View Controller (necesita conectar el botón de salida al ícono de salida de VC y conectarlo para desconectar:

ingrese la descripción de la imagen aquí

  • Relájese Seague Completed -> TextLabel of viewControllerA ha cambiado.

ingrese la descripción de la imagen aquí

Tecnología
fuente