Segue adattivo nello storyboard Xcode 6. Il push è deprecato?


121

Il generatore di interfacce Xcode 6 per impostazione predefinita ha una nuova casella di controllo "usa classi di dimensioni". Rende le visualizzazioni adattive. inserisci qui la descrizione dell'immagine

Quando provo a seguire tra 2 visualizzazioni nel mio storyboard ho nuove opzioni: inserisci qui la descrizione dell'immagine

invece vecchio:

inserisci qui la descrizione dell'immagine

Ora abbiamo "show" e "present modally" invece di "push" e "modal". Le vecchie opzioni sono contrassegnate come deprecate. Ho scelto l'opzione "mostra", perché nelle impostazioni di segue si chiamava "mostra (es. Push)

inserisci qui la descrizione dell'immagine

Ma non fa spinta. L'animazione di Segue appare come una diapositiva dal basso (modale) e la barra di navigazione scompare.

La domanda è: come posso fare in modo che "spettacolo" funzioni come una spinta? È possibile o devo usare "push (deprecated)" invece? Dove posso trovare informazioni sui nuovi tipi di segue? L'unica cosa che ho trovato nella libreria per sviluppatori iOS8 è Storyboard Help You Design Your User Interface, ma non ci sono informazioni su "show" segue.

AGGIORNARE

Ho provato a creare un nuovo progetto e "show" funziona davvero come "push". Penso che il problema nel mio progetto possa essere dovuto al fatto che riutilizzo il controller di navigazione con codice come questo, ma non so come risolverlo.

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

Dopo di che provo a spingere NewViewController dopo MainViewController inserisci qui la descrizione dell'immagine

AGGIORNAMENTO 2:

Sembra che sia solo iOS 7, problema con iOS 7.1.

Risposte:


97

Sì, usa "Mostra" invece di "Spingi"

Come posso far funzionare "show" come push? È possibile o devo usare "push (depricated)" invece?

Dovrebbe; lo fa per me. Sto usando Xcode 6 beta 2 e per testare ho usato il modello di visualizzazione singola (chiamando il controller di visualizzazione prefabbricato in IB 'VC_A'). Ho quindi aggiunto un altro controller di visualizzazione ("VC_B"). Ho quindi aggiunto un pulsante su VC_A per mostrare VC_B e un altro da VC_B a VC_A. Quando aggiungo un controller di navigazione come controller di visualizzazione iniziale nello storyboard e faccio di VC_A il rootViewController, sia "push" che "show" hanno lo stesso effetto. Se non ho un controller di navigazione iniziale e uso 'show' ottengo ciò che hai descritto in quanto il VC_B fa una diapositiva dal basso. Se provo a "spingere" ottengo un crash poiché per fare il push devo avere il controller di navigazione.

Dove posso trovare informazioni sui nuovi tipi di segue?

Quindi ho trovato alcune informazioni nella sessione "Novità di Interface Builder" qui . Se guardi le diapositive vedrai una diapositiva (41) menzionare il cambiamento. Quando guardi il video di quella sessione puoi saltare al minuto 38:00 dove iniziano a parlare di seguiti adattivi. Spiegano che il segue adattivo "mostra", ad esempio, tiene conto del contesto quando si decide come eseguire la presentazione di un nuovo controller di visualizzazione.


La ringrazio per la risposta. Ho provato a creare un nuovo progetto e "show" funziona davvero come push con controller di navigazione. Nel mio progetto ho una struttura complicata con la barra laterale di questa lezione appcoda.com/ios-programming-sidebar-navigation-menu e push funziona, show no. Forse il motivo è che riutilizzo il controller di navigazione. Ho aggiornato la mia domanda con il codice di riutilizzo.
John Kakon

Quindi la prima cosa che vedo quando guardo il tuo aggiornamento è che stai usando il seguito personalizzato previsto: 'SWRevealViewControllerSegue' quindi sì probabilmente non ha senso usare 'show' o 'push' nel tuo caso poiché quelli sono incorporati segue mentre si desidera eseguire il proprio codice personalizzato. Quando scarico il progetto di esempio, viene visualizzato anche la selezione di "personalizzato" sui seguiti nel file dello storyboard.
Spencer Hall

Non intendevo questo segue. Stavo parlando della creazione di un nuovo UIViewController accanto a "MainViewController" (ha il controller di navigazione e il mio "aggiornamento" mostra solo come ottenerlo lì) e tenta di inserire una nuova vista in MainViewController. Screenshot dello storyboard Ti sarò grato se abiliti "usa classi di dimensioni" nel progetto di esempio, crei NewViewController e provi a fare segue tra MainViewController e NewViewController con "show". Vedrai di cosa sto parlando.
John Kakon

L'ho fatto solo ora e almeno per me "spettacolo" ha funzionato proprio come "spingere".
Spencer Hall

9
Puoi aggirare il bug assicurandoti che tutti i modi nel tuo controller di visualizzazione abbiano un UINavigationController alla loro radice. Anche se ciò significa inserire un UINavigationController nel tuo storyboard a cui non si accederà mai. Sembra che il cablaggio venga utilizzato per dedurre il comportamento.
Scott Robertson

33

Esiste già una risposta accettata, ma volevo dare qualche informazione in più, forse informazioni che prima non erano disponibili.

Come accennato in precedenza, le sequenze "push" e "modal" sono state deprecate e sono state sostituite rispettivamente da "show" e "present modally". Secondo la documentazione di Apple, i nuovi passi sono stati ulteriormente suddivisi in seguiti che si adattano alle classi di taglia. I vecchi dovrebbero essere usati solo per supportare le versioni di iOS precedenti a iOS 8.

Il documento nel seguente collegamento lo spiega e la descrizione di tutti i segues disponibili, vecchi e nuovi.

Aggiunta di un segmento tra le scene in uno storyboard

Nel caso in cui l'URL cambi in futuro, questa è la spiegazione fornita per ogni nuovo segue:

Mostrare

Presenta il contenuto nell'area dei dettagli o principale a seconda del contenuto dello schermo. Se l'app mostra una vista principale e dettagliata, il contenuto viene trasferito nell'area dei dettagli. Se l'app mostra solo il master o il dettaglio, il contenuto viene inserito in cima allo stack del controller di visualizzazione corrente.

Mostra i dettagli

Presenta il contenuto nell'area dei dettagli. Se l'app mostra una vista principale e una vista dettagliata, il nuovo contenuto sostituisce il dettaglio corrente. Se l'app mostra solo il master o il dettaglio, il contenuto sostituisce la parte superiore dello stack del controller di visualizzazione corrente.

Presente in modo modale

Presenta il contenuto in modo modale. Sono disponibili opzioni per scegliere uno stile di presentazione (UIModalPresentationStyle) e uno stile di transizione (UIModalTransitionStyle).

Presente come Popover

Presenta il contenuto come popover ancorato a una vista esistente. C'è un'opzione per specificare le possibili direzioni della freccia mostrata su un bordo della vista popover (UIPopoverArrowDirection). C'è anche un'opzione per specificare la vista di ancoraggio.


24

TLDR; Elimina il Segue che non spinge correttamente e ricrealo nello storyboard trascinando da un UIView / UIControl al controller della vista di destinazione.

Non c'è niente di sbagliato nelle altre risposte, ma questa spiega cosa sta succedendo, come puoi verificare che stia accadendo e come mitigare il problema in futuro.

sfondo

Nel mio caso, nessuno dei miei Show Segues funzionava anche se avevo già un UINavigationController come controller di visualizzazione iniziale (con il mio contenuto UIViewController come root).

Perché e come si interrompe lo spettacolo

Lo Show segue si interrompe quando ha un'azione associata al segue all'interno dell'xml di origine dello storyboard. Uno scenario tipico che causa ciò potrebbe essere la ridefinizione di un segue da un segue manuale precedentemente chiamato nel codice. Ciò lascia i seguenti bit nello storyboard xml.

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

Nota Bene Per visualizzare lo storyboard come xml; Fare clic con il pulsante destro del mouse sul file dello storyboard e scegliere Apri come> Codice sorgente . Per ripristinare, utilizzare Apri come> Interface Builder - Storyboard

Per adattare qualsiasi azione personalizzata quando si utilizza il segue dallo storyboard, è sufficiente accedere a prepareForSegue e intercettare il controller della vista di destinazione e chiamare qualsiasi metodo da quella posizione. In ogni caso, l'effetto collaterale di questo piccolo bug (il bug è il fatto che quando ridefinisci il segue non è impostato correttamente in xml ~ cioè l'azione rimane anche dopo aver cambiato il segue con uno che opera da una UIView (o UIControl) a un controller di visualizzazione di destinazione).

Purtroppo la soluzione più diretta fallisce. Quindi la semplice rimozione dell'attributo xml per l'azione dall'interno dello Storyboard NON risolverà il problema. Invece si deve semplicemente eliminare e ricreare il segue nello storyboard.

Una volta ricreato, lo storyboard xml non avrà più un'azione associata al particolare segue e lo Show verrà eseguito come Push.

Xml di esempio per il corretto Show Segue

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

attenuazione

Per prevenire la ricorrenza, è sufficiente attenersi alle sequenze dello storyboard non manuali, se possibile, utilizzando prepareForSegue per aggiungere le azioni richieste in base al controller della vista di destinazione. Oppure, se devi combinare e abbinare, prendi la precauzione per verificare che i tuoi seguiti dello spettacolo non abbiano alcuna azione allegata nello storyboard xml. Se hai a che fare con progetti più vecchi, dovresti prestare particolare attenzione al codice sorgente dello Storyboard poiché ho scoperto alcuni problemi.


3
Dopo ore, questo probabilmente mi ha risparmiato altre ore. Ecco cosa suggerirei in base a quanto sopra: apri lo storyboard come codice sorgente , cerca kind = "show" e guarda se la riga contiene qualcosa come action = "showDetailViewController: sender:" , in tal caso, elimina tutto dall'azione = fino alla chiusura " . Ho uno storyboard davvero enorme e la sequenza interessata non conteneva questo parametro di azione, ma un'altra riga non correlata sì. Una volta eliminata l'azione, tutte le sequenze adattive hanno funzionato di nuovo come previsto. La sola eliminazione della sequenza interessata non ha funzionato" t lavoro.
Marco

Anche questo mi ha salvato.
Adam Bardon

1
L'eliminazione dell'attributo di azione nell'XML ha funzionato per il mio amico.
Brent Royal-Gordon

ha salvato anche me
Jimmy George Thomas

Eliminato l'attributo action nel file xml e voilà, funziona. Non avrei mai trovato il problema senza questo post.
krizzzn

20

Come ha commentato qui Scott Robertson , questo sembra un bug in iOS 7.

Sembra che in iOS 8 la transizione venga dedotta in fase di esecuzione (comportamento corretto), mentre in iOS 7 la transizione venga dedotta in fase di progettazione (comportamento buggy).

La soluzione più semplice è aggiungere un controller di navigazione inutilizzato allo storyboard e collegarlo in modo che il controller di visualizzazione in questione faccia parte di questo controller di navigazione. In realtà non è necessario creare un'istanza del controller di navigazione, è sufficiente che il controller di visualizzazione difettoso sappia che è incorporato in un controller di navigazione.

Nota: la simulazione di una barra di navigazione non è sufficiente per questi scopi; devi effettivamente avere un controller di navigazione nel suo push stack.

Per riprodurre il bug:

  1. Crea un nuovo storyboard che utilizza classi di dimensioni.
  2. Crea due controller di visualizzazione (nessun controller di navigazione).
  3. Fai in modo che il primo controller di visualizzazione mostri il secondo controller di visualizzazione tramite un segue Show (ad esempio Push) collegato a un pulsante, ad esempio.
  4. Nel codice, mostra il primo controller di visualizzazione, ma incorporalo in un controller di navigazione tramite il initWithRootViewController:metodo.
  5. Esegui l'app su iOS 7.
  6. Tocca il pulsante che dovrebbe eseguire la spinta.
  7. Otterrai una transizione modale invece di un push su iOS 7. Su iOS 8 otterrai il comportamento push corretto.

inserisci qui la descrizione dell'immagine

Per correggere il bug:

  1. Aggiungi un controller di navigazione allo storyboard e imposta il primo controller di visualizzazione come controller di visualizzazione principale. (Nota: l'aggiunta del secondo come controller di visualizzazione root NON risolverà questo bug.)
  2. Dagli un identificatore di posta indesiderata per sopprimere l'avvertimento relativo all'inaccessibilità del controller di navigazione e per documentarti che esiste esclusivamente come soluzione alternativa. (ad esempio workaround for show segues in iOS 7).

inserisci qui la descrizione dell'immagine

Notare come il controller di navigazione è stato aggiunto nella seconda immagine e come non ha frecce in arrivo (cioè non c'è modo di istanziarlo se non usando il suo identificatore del controller di visualizzazione).


1
Grazie, il trucco con il NavigationController ha funzionato per me quando ho cambiato lo stack di NavigationControllers ViewController di root
Peter Pint

1
Soluzione migliore. Grazie
Илья Голованов

13

So di essere in ritardo ma volevo condividere ciò che ho imparato. Questo è infatti un bug ed è ancora presente oggi (2014-12-18).

Ho scritto un articolo su questo qui .

È facilmente riproducibile; su iOS8 funzionerà perfettamente e anche in iOS7.x fintanto che non si inserisce un controller di visualizzazione a livello di codice nello stack prima di chiamare Showsegue.

Se esegui il push nello stack solo utilizzando le connessioni storyboard, funzionerà; ma a quanto pare se si esegue il push tramite codice in qualche modo la navigationControllerproprietà del pushed UIViewControllersarà nile quando lo si chiama Showassumerà che sia un modale perché non c'è navigazione per controllare lo stack.

L'unica soluzione alternativa finora è non eseguire il push tramite codice (non fattibile) o utilizzare l'ormai deprecato Push.

Ho presentato un radar (link sull'articolo). Sentiti libero di presentare duplicati con la speranza che Apple risolva questo problema.


3
Questo era esattamente il mio problema, grazie! in questo caso l'utilizzo di push deprecato sembra essere la soluzione meno dannosa.
Moshe Gottlieb

Un'altra soluzione alternativa consiste nell'aggiungere un controller di navigazione (non utilizzato) allo storyboard. Vedere stackoverflow.com/questions/24184003/...
Senseful

Nop! Sta accadendo qui e la causa non è una spinta programmatica. Nel mio caso Showeseguo un segue, quindi sul secondo Showsegue viene presentato in modo modale, Soluzione?
Frade

@Frade puoi collegarti a un repository GitHub dove questo è riproducibile? Su quale versione di iOS stai utilizzando?
esttorhe

progetto privato .. ShowSuccede quando si tenta di eseguire un (secondo) di un ViewController su iOS 7
Frade

2

Ho avuto lo stesso problema con i segues in Xcode 7 e iOS 7.1.2. Mostra segues (nuova funzionalità di iOS 8) funziona come segues modali in iOS 7 e non ti consente di inserire i tuoi View Controller nello stack del controller di navigazione quando definisci il tipo segue con Xcode nello Storyboard. Ecco perché il tuo self.navigationController restituirà zero, perché il controller di visualizzazione non è stato inserito nello stack e non puoi visualizzarlo.

Non capisco perché Apple non abbia aggiunto alcuna notifica per questo caso in Xcode quando è necessario che la tua app funzioni su iOS 7. Dicono che il metodo Push è deprecato, ma Show non funziona correttamente con iOS 7.

Cosa ho fatto per risolvere il problema:

Ho creato la classe MYShowSegue con .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

E file .m con un solo metodo di esecuzione :

#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

Quindi devi impostare un tipo personalizzato per ogni segue nel tuo Storyboard e selezionare una nuova classe per esso, nel mio caso era MYShowSegue.

Esempio di segue personalizzato

Questa soluzione ti aiuterà a ottenere un supporto completo delle tue app iOS 7, useranno il metodo pushViewController per spingere le tue visualizzazioni e per iOS 8,9 ecc. Il tuo segue funzionerà con il nuovo metodo (iOS 8) showViewController

Non dimenticare di fare lo stesso con tutti i tuoi seguiti nel tuo Storyboard.


Bella soluzione - ha funzionato per me (invece di aggiungere un controller di navigazione "inutilizzato" ...
Laurenz Glück

1

Questo sta ancora accadendo in iOS 10.x

L'eliminazione e il ripristino di segues non ha risolto nulla per me:

Problema: la funzionalità richiesta era di 7 passaggi che funzionano solo come "push" (in realtà un dettaglio dello spettacolo) ma in realtà solo il primo segue che ho aggiunto spingerebbe, gli altri si comportano tutti in modo modale. Questo nonostante Interface Builder descriva ciascuna delle sequenze in modo identico.

Soluzione: ho dovuto aggiungere l'azione ai 6 segues che non l'avevano.

Storyboard XML originale

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

L'ho cambiato aggiungendo showViewController: sender

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.