Segue adaptativo en el storyboard Xcode 6. ¿Se desactivó el push?

121

El constructor de interfaz Xcode 6 por defecto tiene una nueva casilla de verificación "usar clases de tamaño". Hace que las vistas sean adaptativas. ingrese la descripción de la imagen aquí

Cuando intento hacer una transición entre 2 vistas en mi guión gráfico, tengo nuevas opciones: ingrese la descripción de la imagen aquí

en vez viejo:

ingrese la descripción de la imagen aquí

Ahora tenemos "show" y "present modally" en lugar de "push" y "modal". Las opciones anteriores están marcadas como obsoletas. Elegí la opción "mostrar", porque en la configuración segue se llamaba "mostrar (por ejemplo, presionar)

ingrese la descripción de la imagen aquí

Pero no hace empuje. La animación Segue parece una diapositiva desde la parte inferior (modal) y la barra de navegación desaparece.

La pregunta es: ¿Cómo puedo hacer que "show" funcione como push? ¿Es posible o debería usar "push (obsoleto)" en su lugar? ¿Dónde puedo encontrar información sobre nuevos tipos de segue? Lo único que he encontrado en la biblioteca para desarrolladores de iOS8 es Storyboards Help You Design Your User Interface pero no hay información sobre el "show" segue.

ACTUALIZAR

Traté de crear un nuevo proyecto y "show" realmente funciona como "push". Creo que el problema en mi proyecto puede ser porque reutilizo el controlador de navegación con un código como este, pero no sé cómo solucionarlo.

if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
    SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
    
    swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
        
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    };
    
}

Después de eso trato de empujar NewViewController después de MainViewController ingrese la descripción de la imagen aquí

ACTUALIZACIÓN 2:

Parece ser solo un problema de iOS 7, iOS 7.1.

John Kakon
fuente

Respuestas:

97

Sí, use 'Mostrar' en lugar de 'Empujar'

¿Cómo puedo hacer que "show" funcione como push? ¿Es posible o debería usar "push (depricated)" en su lugar?

Debería; lo hace por mi Estoy usando Xcode 6 beta 2 y para probar usé la plantilla de vista única (llamando al controlador de vista prefabricado en IB 'VC_A'). Luego agregué otro controlador de vista ('VC_B'). Luego agregué un botón en VC_A para mostrar VC_B y otro de VC_B a VC_A. Cuando agrego un controlador de navegación como el controlador de vista inicial en el guión gráfico y hago que VC_A sea rootViewController, tanto 'push' como 'show' tienen el mismo efecto. Si no tengo un controlador de navegación inicial y uso 'show', obtengo lo que describiste en que el VC_B se desliza hacia arriba desde la parte inferior. Si trato de "empujar" me cuelgo, ya que para hacerlo debo tener un controlador de navegación.

¿Dónde puedo encontrar información sobre nuevos tipos de segue?

Así que encontré información en la sesión 'Novedades en el Creador de interfaces' aquí . Si observa las diapositivas, verá una diapositiva (41) que menciona el cambio. Al mirar el video de la sesión, puede saltar al minuto 38:00, donde comienzan a hablar sobre segues adaptativos. Explican que el segmento adaptativo 'mostrar', por ejemplo, tiene en cuenta el contexto al decidir cómo hacer la presentación de un nuevo controlador de vista.

Spencer Hall
fuente
Gracias por su respuesta. Traté de crear un nuevo proyecto y "mostrar" realmente funciona como empujar con el controlador de navegación. En mi proyecto, tengo una estructura complicada con la barra lateral de esta lección appcoda.com/ios-programming-sidebar-navigation-menu y push works, show does not. Puede ser la razón es que reutilizo el controlador de navegación. He actualizado mi pregunta con el código de reutilización.
John Kakon
Entonces, lo primero que veo al mirar su actualización es que está utilizando una espera personalizada: 'SWRevealViewControllerSegue', así que sí, probablemente no tenga sentido usar 'show' o 'push' en su caso, ya que están integrados segues mientras que desea ejecutar su propio código personalizado. Cuando descargo el proyecto de muestra, incluso muestra la selección de 'personalizado' en los segmentos del archivo del guión gráfico.
Spencer Hall
No quise decir esto. Estaba hablando de crear un nuevo UIViewController al lado de "MainViewController" (tiene un controlador de navegación, y mi "actualización" solo muestra cómo lo llevo allí) e intenta insertar una nueva vista en MainViewController. Captura de pantalla del guión gráfico Estaré agradecido si habilita "usar clases de tamaño" en el proyecto de muestra, crea NewViewController e intenta hacer una transición entre MainViewController y NewViewController mediante "show". Verás de qué estoy hablando.
John Kakon
Lo hice justo ahora y al menos para mí "show" funcionó como "push".
Spencer Hall
9
Puede solucionar el error asegurándose de que todas las formas en su controlador de vista tengan un UINavigationController en su raíz. Incluso si eso significa poner un UINavigationController en su guión gráfico al que nunca se accederá. Parece que el cableado se usa para inferir el comportamiento.
Scott Robertson
33

Ya hay una respuesta aceptada, pero quería dar un poco más de información, posiblemente información que antes no estaba disponible.

Como se mencionó anteriormente, los segmentos "push" y "modal" quedaron en desuso y han sido reemplazados por "show" y "present modally" respectivamente. Según la documentación de Apple, los nuevos segmentos se han dividido en segmentos que se adaptan a las clases de tamaño. Los más antiguos solo deben usarse para admitir versiones de iOS anteriores a iOS 8.

El documento en el siguiente enlace explica eso y la descripción de todos los segmentos disponibles, antiguos y nuevos.

Agregar una secuencia entre escenas en un guión gráfico

En caso de que la URL cambie en el futuro, esta es la explicación dada para cada nuevo segmento:

mostrar

Presente el contenido en el área de detalle o maestra según el contenido de la pantalla. Si la aplicación muestra una vista maestra y de detalles, el contenido se inserta en el área de detalles. Si la aplicación solo muestra el maestro o el detalle, el contenido se coloca en la parte superior de la pila del controlador de vista actual.

Mostrar detalle

Presente el contenido en el área de detalle. Si la aplicación muestra una vista maestra y detallada, el nuevo contenido reemplaza al detalle actual. Si la aplicación solo muestra el maestro o el detalle, el contenido reemplaza la parte superior de la pila del controlador de vista actual.

Presente modalmente

Presentar el contenido modalmente. Hay opciones para elegir un estilo de presentación (UIModalPresentationStyle) y un estilo de transición (UIModalTransitionStyle).

Presente como Popover

Presente el contenido como un popover anclado a una vista existente. Hay una opción para especificar las posibles direcciones de la flecha que se muestra en un borde de la vista emergente (UIPopoverArrowDirection). También hay una opción para especificar la vista de anclaje.

alondono
fuente
24

tldr; Elimine el Segue que no está presionando correctamente y vuelva a crearlo en el guión gráfico arrastrándolo desde un UIView / UIControl al controlador de vista de destino.

No hay nada malo con las otras respuestas, pero esta explica lo que está sucediendo, cómo puede verificar que está sucediendo y cómo mitigar el problema en el futuro.

Antecedentes

En mi caso, ninguno de mis Show Segues funcionaba a pesar de que ya tenía un UINavigationController como mi controlador de vista inicial (con mi contenido UIViewController como root).

Por qué y cómo se rompe el espectáculo Segue

Show segue se rompe cuando tiene una acción asociada con el segue dentro del xml fuente del guión gráfico. Un escenario típico que causa esto podría ser si ha redefinido una secuencia de una secuencia manual previamente llamada en código. Esto deja los siguientes bits en el storyboard xml.

<connections>
    <segue destination="85t-Z1-hxf" kind="show" identifier="ToOptions" action="showDetailViewController:sender:" id="gdZ-IX-KcN">
</connections>

Nota Bene Para ver el guión gráfico como xml; Haga clic derecho en el archivo del guión gráfico y elija Abrir como> Código fuente . Para revertir, use Abrir como> Generador de interfaces - Storyboard

Para acomodar cualquier acción personalizada cuando se usa el segue del guión gráfico, uno puede acceder a prepareForSegue e interceptar el controlador de vista de destino y llamar a cualquier método desde esa ubicación. En cualquier caso, el efecto secundario de este pequeño error (el error es el hecho de que cuando redefine el segue no se configura correctamente en xml ~ es decir, la acción permanece incluso después de cambiar el segue a uno que opera desde una UIView (o UIControl) a un controlador de vista de destino).

Lamentablemente, la solución más directa falla. Entonces, solo eliminar el atributo xml para la acción desde Storyboard NO solucionará el problema. En cambio, uno simplemente tiene que eliminar y recrear la secuencia en el guión gráfico.

Cuando se vuelve a crear el storyboard xml ya no tendrá una acción asociada con el segmento particular y el Show se ejecutará como un Push.

Xml de muestra para Show Segue correcto

  <connections>
    <segue destination="RbV-Au-WV9" kind="show" identifier="ToOptions" id="5dm-os-bcS"/>
  </connections>

Mitigación

Para evitar la recurrencia, uno solo debe apegarse a la segmentación de guiones gráficos no manuales, si es posible, utilizando prepareForSegue para agregar las acciones requeridas basadas en el controlador de vista de destino. O si tiene que mezclar y combinar, tome la precaución de verificar que su segue Show no tenga ninguna acción adjunta en el storyboard xml. Si se trata de proyectos más antiguos, debe prestar especial atención al código fuente de Storyboard, ya que descubrí algunos problemas.

Tommie C.
fuente
3
Después de horas, esto me salvó probablemente algunas otras horas. Esto es lo que sugeriría en base a lo anterior: abra el guión gráfico como código fuente , busque kind = "show" y busque si la línea contiene algo como action = "showDetailViewController: sender:" , si es así, elimine todo de la acción = hasta el cierre " . Tengo un guión gráfico realmente enorme y la secuencia afectada no contenía este parámetro de acción, pero sí otra línea no relacionada. Una vez que eliminé la acción, todas las secuencias adaptativas funcionaron de nuevo como se esperaba. Simplemente eliminar la secuencia afectada no t trabajo.
Marcus
Esto también me salvó.
Adam Bardon el
1
Eliminar el atributo de acción en el XML funcionó para mi amigo.
Brent Royal-Gordon
me salvó también
Jimmy George Thomas
Eliminado el atributo de acción en el archivo xml, y listo, funciona. Nunca habría encontrado el problema sin esta publicación.
krizzzn
20

Como Scott Robertson comentó aquí , esto parece un error en iOS 7.

Parece que en iOS 8 la transición se infiere en tiempo de ejecución (comportamiento correcto), mientras que en iOS 7 la transición se infiere en tiempo de diseño (comportamiento con errores).

La solución más simple es agregar un controlador de navegación no utilizado al guión gráfico y vincularlo para que el controlador de vista en cuestión sea parte de este controlador de navegación. En realidad, no tiene que crear una instancia del controlador de navegación, solo necesita el controlador de vista con errores para saber que está incrustado en un controlador de navegación.

Nota: Simular una barra de navegación no es suficiente para estos fines; en realidad debe tener un controlador de navegación en su pila de inserción.

Para reproducir el error:

  1. Cree un nuevo guión gráfico que use clases de tamaño.
  2. Cree dos controladores de vista (sin controladores de navegación).
  3. Haga que el primer controlador de vista muestre el segundo controlador de vista a través de un segmento Mostrar (por ejemplo, Push) vinculado a un botón, por ejemplo.
  4. En el código, muestre el primer controlador de vista, pero incrústelo en un controlador de navegación a través del initWithRootViewController:método.
  5. Ejecute la aplicación en iOS 7.
  6. Toque el botón que debe realizar el empuje.
  7. Obtendrá una transición modal en lugar de una inserción en iOS 7. En iOS 8 obtendrá el comportamiento correcto de inserción.

ingrese la descripción de la imagen aquí

Para arreglar el error:

  1. Agregue un controlador de navegación al guión gráfico y configure el primer controlador de vista para que sea el controlador de vista raíz. (Nota: agregar el segundo como el controlador de vista raíz NO solucionará este error).
  2. Déle un identificador de correo no deseado para suprimir la advertencia de que el controlador de navegación es inaccesible y documentarse a sí mismo que existe únicamente como una solución alternativa. (por ejemplo workaround for show segues in iOS 7)

ingrese la descripción de la imagen aquí

Observe cómo se agregó el controlador de navegación en la segunda imagen y cómo no tiene flechas entrantes (es decir, no hay forma de crear una instancia que no sea usando su identificador de controlador de vista).

Sensato
fuente
1
Gracias, el truco con el NavigationController lo hizo por mí cuando estoy intercambiando la raíz de NavigationControllers ViewController-Stack
Peter Pint
1
Mejor solución. Gracias
Илья Голованов
13

Sé que llego tarde a esto, pero quería compartir lo que aprendí. De hecho, esto es un error y todavía está presente hoy (18/12/2014).

Escribí un artículo sobre esto aquí .

Es fácilmente reproducible; en iOS8 funcionará bien e incluso en iOS7.x siempre que no inserte un controlador de vista mediante programación en la pila antes de llamar al Showsegue.

Si solo empujas a la pila usando las conexiones del guión gráfico, funcionará; pero aparentemente si empuja a través del código de alguna manera, la navigationControllerpropiedad del empujado UIViewControllerserá nily cuando lo llame Showasumirá que es modal porque no hay navegación para controlar la pila.

La única solución hasta el momento es no presionar a través del código (no es factible) o usar el ahora obsoleto Push.

Archivé un radar (enlace en el artículo). Siéntase libre de presentar duplicados con la esperanza de que Apple solucione este problema.

esttorhe
fuente
3
Este fue exactamente mi problema, ¡gracias! El uso de push obsoleto parece ser la solución menos malvada en este caso.
Moshe Gottlieb
Otra solución es agregar un controlador de navegación (no utilizado) al guión gráfico. Ver stackoverflow.com/questions/24184003/…
Senseful
Nop! Está sucediendo aquí y la causa no es un impulso programático. En mi caso realizo un Showsegue, luego en el segundo Showsegue se presenta modalmente, ¿Solución?
Frade
@Frade, ¿puede vincular a un repositorio de Github donde esto es reproducible? ¿Estás ejecutando en qué versión de iOS?
Esttorhe
proyecto privado. ShowSucede cuando se intenta realizar un (segundo) de un viewController en iOS 7
Frade
2

Tuve el mismo problema con segues en Xcode 7 e iOS 7.1.2. Show segues (nueva característica de iOS 8) funciona como segues modales en iOS 7 y no le permite empujar sus controladores de vista a la pila del controlador de navegación cuando define el tipo de segue con Xcode en su Storyboard. Es por eso que su self.navigationController devolverá nulo, porque el Controlador de vista no fue empujado a la pila y no puede abrirlo.

No entiendo por qué Apple no agregó ninguna notificación para este caso en Xcode cuando necesita que su aplicación funcione en iOS 7. Dicen que el método Push está en desuso, pero Show no funciona correctamente con iOS 7.

¿Qué hice para resolver el problema?

He creado la clase MYShowSegue con .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

Y el archivo .m con un solo método de ejecución :

#import "MYShowSegue.h"

@implementation MYShowSegue

- (void) perform {

    if ([[[self sourceViewController] navigationController] respondsToSelector:@selector(showViewController:sender:)]) {

        id sender = nil;
        [[[self sourceViewController] navigationController] showViewController:[self destinationViewController] sender:sender];
    }else{

        [[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:YES];
    }
}

@end

De lo que necesita establecer un tipo personalizado para cada segmento en su Storyboard y seleccionar una nueva clase para él, en mi caso fue MYShowSegue.

Ejemplo de Segue personalizado

Esta solución lo ayudará a obtener un soporte completo de sus aplicaciones iOS 7, usarán el método pushViewController para impulsar sus Vistas y para iOS 8,9, etc. su segue funcionará con el nuevo método (iOS 8) showViewController

No olvides hacer lo mismo con todos tus segmentos en tu Storyboard.

Igor Tikhonov
fuente
Buena solución: funcionó para mí (en lugar de agregar un controlador de navegación "no utilizado" ...
Laurenz Glück
1

Esto sigue sucediendo en iOS 10.x

Eliminar y volver a instalar segues no me resolvió nada:

Problema: la funcionalidad requerida era de 7 segues, que solo funcionan como un "push" (en realidad, un show Detail) pero, de hecho, solo el primer segue que agregué empujaría, los demás se comportarían modalmente. Esto a pesar de que Interface Builder describe cada uno de los segmentos de forma idéntica.

Solución: tuve que agregar la acción a los 6 segmentos que no la tenían.

Storyboard original XML

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" id="3NK-93-wTy"/>
</connections>

Cambié esto agregando showViewController: remitente

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" action="showViewController:sender:" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" action="showViewController:sender:" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" action="showViewController:sender:" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" action="showViewController:sender:" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" action="showViewController:sender:" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" action="showViewController:sender:" id="3NK-93-wTy"/>
</connections>
Damo
fuente