La creazione di un segue a livello di codice


202

Ho un comune UIViewControllerche tutti i miei UIViewsControllerssforzi per riutilizzare alcune operazioni comuni.

Voglio creare un seguito su questo "comune" in UIViewControllermodo che tutti gli altri UIViewControllersereditino.

Sto cercando di capire come posso farlo a livello di codice.

Immagino che la domanda potrebbe anche essere come faccio a impostare un segueper tutti i miei UIViewControllerssenza entrare nella storyboard e farli a mano.

Risposte:


169

Per definizione, un follow non può realmente esistere indipendentemente da uno storyboard. E 'ancora lì nel nome della classe: UIStoryboardSegue. Non crei follower a livello di codice: è il runtime dello storyboard che li crea per te. Normalmente puoi chiamare performSegueWithIdentifier:il codice del tuo controller di visualizzazione, ma questo si basa sul fatto che un storyboard sia già impostato nello storyboard come riferimento.

Quello che penso che ti stai chiedendo è come puoi creare un metodo nel tuo controller di visualizzazione comune (classe base) che passerà a un nuovo controller di vista e sarà ereditato da tutte le classi derivate. È possibile farlo creando un metodo come questo sul controller della vista della classe base:

- (IBAction)pushMyNewViewController
{
    MyNewViewController *myNewVC = [[MyNewViewController alloc] init];

    // do any setup you need for myNewVC

    [self presentModalViewController:myNewVC animated:YES];
}

e quindi nella classe derivata, chiamare quel metodo quando si fa clic sul pulsante appropriato o si seleziona la riga della tabella o altro.


4
Grazie. È un peccato che non possiamo farlo programmaticamente. Aumenterebbe davvero la qualità del codice sorgente (meno duplicazioni è sempre buona). Ci proverò con il tuo suggerimento.
Tiago Veloso,

2
@jonkroll è possibile chiamare / eseguire segue dall'istruzione switch, ovvero in base a quale indice ho?
codejunkie,

5
@codejunkie: Sì, puoi farlo. Utilizzeresti il UIViewControllermetodo chiamato performSegueWithIdentifier:sender:per questo.
jonkroll,

2
Ho creato ed eseguito segue in modo programmatico (vedi la mia risposta). Qualcosa non va nel mio codice, quindi, se la tua risposta è corretta?
Jean-Philippe Pellet,

13
Aggiornamento per iOS 6+: UIView's presentModalViewController:animated:è deprecato. Dai documenti - (Obsoleto in iOS 6.0. Usa presentViewController: animato: completamento: invece.)
utente

346

Ho pensato di aggiungere un'altra possibilità. Una delle cose che puoi fare è collegare due scene in uno storyboard usando un seguito che non è associato a un'azione e quindi attivare a livello di codice il seguito all'interno del controller della vista. Il modo in cui lo fai è che devi trascinare dall'icona del proprietario del file nella parte inferiore della scena dello storyboard che è la scena successiva e trascinare a destra sulla scena di destinazione. Lancio un'immagine per aiutare a spiegare.

inserisci qui la descrizione dell'immagine

Verrà visualizzato un popup per "Segue manuale". Ho scelto Push come tipo. Tocca il quadratino e assicurati di essere nella finestra di ispezione degli attributi. Dagli un identificatore che userai per fare riferimento ad esso nel codice.

inserisci qui la descrizione dell'immagine

Ok, dopo seguirò usando una voce del pulsante della barra programmatica. In viewDidLoad o da qualche altra parte creerò un elemento pulsante sulla barra di navigazione con questo codice:

UIBarButtonItem *buttonizeButton = [[UIBarButtonItem alloc] initWithTitle:@"Buttonize"
                                                                    style:UIBarButtonItemStyleDone
                                                                   target:self
                                                                   action:@selector(buttonizeButtonTap:)];
self.navigationItem.rightBarButtonItems = @[buttonizeButton];

Ok, nota che il selettore è buttonizeButtonTap :. Quindi scrivi un metodo vuoto per quel pulsante e all'interno di quel metodo chiamerai il seguente in questo modo:

-(void)buttonizeButtonTap:(id)sender{
    [self performSegueWithIdentifier:@"Associate" sender:sender];
    }

Il parametro mittente è necessario per identificare il pulsante quando viene chiamato preparForSegue. preparForSegue è il metodo framework in cui istanzerai la tua scena e le passerai tutti i valori necessari per fare il suo lavoro. Ecco come appare il mio metodo:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"Associate"])
    {
        TranslationQuizAssociateVC *translationQuizAssociateVC = [segue destinationViewController];
        translationQuizAssociateVC.nodeID = self.nodeID; //--pass nodeID from ViewNodeViewController
        translationQuizAssociateVC.contentID = self.contentID;
        translationQuizAssociateVC.index = self.index;
        translationQuizAssociateVC.content = self.content;
    }
}

Ok, l'ho appena provato e funziona. Spero che ti aiuti.


@MichaelRowe in che modo questo elimina la necessità di segues? A mio modo di vedere, devi ancora trascinare e rilasciare lo Storyboard sul controller di destinazione ..
aherrick,

@MichaelRowe questo non elimina la necessità di segues. Ciò consente di seguire i controller di visualizzazione integrati nel codice anziché nel builder di interfacce.
Matteo,

@Matt in realtà mi fa solo ripensare completamente il modo in cui ho configurato la mia app ... Dopo una riscrittura completa di tutta l'interfaccia utente non uso più alcun segues ..
Michael Rowe,

@cocoanut sto ricevendo l'errore poiché "L'applicazione ha cercato di presentare modalmente un controller attivo" qualsiasi aiuto in merito ..
Bala

1
Segue manuale "Push" è obsoleto, utilizzare "Mostra". Questa risposta ha maggiori dettagli. @smileBot si prega di aggiornare la risposta.
NAbbas

81

Ho usato questo codice per creare un'istanza della mia sottoclasse segue personalizzata ed eseguirlo a livello di codice. Sembra funzionare Qualcosa non va in questo? Sono perplesso, leggendo tutte le altre risposte dicendo che non si può fare.

UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"OtherViewControllerId"];
MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:@"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];

4
Cosa c'è in MyCustomSegue?
Victor Engel,

3
È una sottoclasse personalizzata di UIStoryboardSegue.
Jean-Philippe Pellet,

7
@MarkAmery Molte persone (incluso me) evitano di usare gli storyboard. Sono difficili da fusione, e non c'è nessun controllo in fase di compilazione che l'ID sto passando a performSegueWithIdentifier:è davvero definito nello storyboard. Evito tutti i problemi se creo il seguito da solo.
Jean-Philippe Pellet,

3
Sono d'accordo con Jean-Philippe. Gestire lo storyboard è una seccatura. Ovviamente è facile fare clic per aprire alcune viste e aggiungere un seguito qui e un seguito lì, ma gestire 6 viste con 16 seguiti definiti in XML, quando hai tre sviluppatori che si armeggiano con esso è terribile. Comunque, il punto è: il codice ti dà il controllo, xml generato da xcode no.
Krystian,

3
Vedo un arresto anomalo in [segue perform] in iOS7, non sono sicuro se qualcun altro lo sta vivendo.
Eric Chen,

45

Immagino che questa sia una risposta accettata, ma vorrei solo aggiungere qualche dettaglio in più.

Cosa ho fatto per risolvere un problema in cui avrei presentato una vista di accesso come prima schermata e poi volevo seguire l'applicazione se l'accesso fosse corretto. Ho creato il seguito dal controller della vista di accesso al controller della vista principale e gli ho dato un identificativo come "myidentifier".

Quindi, dopo aver verificato tutto il codice di accesso se l'accesso fosse corretto, chiamerei

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

Il mio più grande fraintendimento fu che provai a mettere il seguito su un pulsante e in qualche modo interrompevo il seguito una volta trovato.


4
Come ho scritto come un altro commento: sto creando ed eseguendo follower personalizzati a livello di codice (vedi la mia risposta).
Jean-Philippe Pellet,

32

Devi collegare il tuo codice a UIStoryboardquello che stai utilizzando. Assicurati di entrare in YourViewController nel tuo UIStoryboard, fai clic sul bordo attorno ad esso, quindi imposta il suo identifiercampo su NSStringquello che chiami nel tuo codice.

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                                                     bundle:nil];
YourViewController *yourViewController = 
 (YourViewController *)
  [storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerID"];
[self.navigationController pushViewController:yourViewController animated:YES];

1
Ho capito, ma cosa succede se il viewController che voglio presentare è incorporato in un NavigationController nello storyboard? Da quello che posso trovare, posso inizializzare un NavigationController per incorporarlo ma nello storyboard, ho già la configurazione push segues per la vista che deve essere presentata.
jhilgert00,

1
puoi approfondire questo? Penso che questo sia il problema che sto riscontrando, ma non riesco a trovare come / dove farlo ...
jesses.co.tt

1
Anche questa soluzione è corretta, si tratta di evitare qualsiasi seguito, ma la domanda riguarda segue. In questo modo puoi connetterti o effettuare una transizione tra due scene SENZA seguire negli storyboard.
BootMaker,

16

Per i controller che si trovano nello storyboard.

jhilgert00 è questo quello che stavi cercando?

-(IBAction)nav_goHome:(id)sender {
UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:@"HomeController"];
[self.navigationController pushViewController: myController animated:YES];

}

O...

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


3

Vorrei aggiungere un chiarimento ...

Un malinteso comune, in effetti uno che ho avuto per qualche tempo, è che uno storyboard segue è innescato dal prepareForSegue:sender:metodo. Non è. Seguirà uno storyboard, indipendentemente dal fatto che tu abbia implementato un prepareForSegue:sender:metodo per quel controller di vista (in partenza da).

L'ho imparato dalle eccellenti lezioni su iTunesU di Paul Hegarty . Mi scuso ma purtroppo non ricordo quale lezione.

Se si collega un segue tra due controller di vista in uno storyboard, ma non si implementa un prepareForSegue:sender:metodo, il seguito seguirà comunque il controller di vista di destinazione. Seguirà tuttavia tale controller di visualizzazione non preparato.

Spero che questo ti aiuti.


3

Storyboard Segues non devono essere creati al di fuori dello storyboard. Dovrai collegarlo, nonostante gli svantaggi.

UIStoryboardSegue Reference afferma chiaramente:

Non si creano oggetti segue direttamente. Al contrario, il runtime dello storyboard li crea quando deve eseguire un follow tra due controller di visualizzazione. È comunque possibile avviare a segue a livello di codice utilizzando performSegueWithIdentifier: mittente: metodo di UIViewController, se lo si desidera. È possibile farlo per avviare un seguito da una fonte che è stata aggiunta a livello di codice e quindi non disponibile in Interface Builder.

Puoi ancora dire a livello di codice allo storyboard di presentare un controller di visualizzazione utilizzando un utilizzo successivo presentModalViewController:o pushViewController:animated:chiamate, ma avrai bisogno di un'istanza dello storyboard.

Puoi chiamare UIStoryboardil metodo class per ottenere uno storyboard con nome con bundle nil per il bundle principale.

storyboardWithName:bundle:


2

Prima di tutto, supponi di avere due diverse visualizzazioni nello storyboard e desideri spostarti da una schermata all'altra, quindi segui questi passaggi:

1). Definisci tutte le tue visualizzazioni con il file di classe e anche l'id storyboard nella finestra di ispezione identità.

2). Assicurati di aggiungere un controller di navigazione alla prima vista. Selezionalo nello Storyboard e quindi Editor> Incorpora in> Controller di navigazione

3). Nella tua prima classe, importa "secondClass.h"

#import "ViewController.h
#import "secondController.h"

4). Aggiungere questo comando nell'IBAction che deve eseguire i seguenti

secondController *next=[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
[self.navigationController pushViewController:next animated:YES];

5). @"second"è la classe controller di secondview, id storyboard.


self.storyboarddovrebbe essere:UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
masipcat,

@masipcat e il nome della storyboard potrebbero dipendere da come hai impostato il tuo progetto Xcode, nel mio era "Main.storyboard" quindi l'ho usatostoryboardWithName:@"Main"
ammianus,

@ sanket-chauhan se il tuo primo controller non è incorporato in un controller di navigazione, puoi anche mostrare la vista successiva usando [self showDetailViewController:next sender:self];o[self showViewController:next sender:self];
ammianus,

1

Ho retroingegnerizzato e realizzato una (re) implementazione open source dei segues di UIStoryboard: https://github.com/acoomans/Segway

Con quella libreria, puoi definire segues a livello di codice (senza storyboard).

Spero possa essere d'aiuto.


0

Un paio di problemi, in realtà:

Innanzitutto, nel progetto che hai caricato per noi, il seguito non porta l'identificatore "segue1":

nessun identificatore

Dovresti inserire quell'identificatore se non l'hai già fatto.

In secondo luogo, mentre si passa dalla vista tabella alla vista tabella, si chiama initWithNibName per creare un controller vista. Vuoi davvero usare instantiateViewControllerWithIdentifier.


0

Ecco l'esempio di codice per Creating a segue programmatically:

class ViewController: UIViewController {
    ...
    // 1. Define the Segue
    private var commonSegue: UIStoryboardSegue!
    ...
    override func viewDidLoad() {
        ...
        // 2. Initialize the Segue
        self.commonSegue = UIStoryboardSegue(identifier: "CommonSegue", source: ..., destination: ...) {
            self.commonSegue.source.showDetailViewController(self.commonSegue.destination, sender: self)
        }
        ...
    }
    ...
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 4. Prepare to perform the Segue
        if self.commonSegue == segue {
            ...
        }
        ...
    }
    ...
    func actionFunction() {
        // 3. Perform the Segue
        self.prepare(for: self.commonSegue, sender: self)
        self.commonSegue.perform()
    }
    ...
}

Stai chiamando self.prepare(for: self.commonSegue, sender: self)dal tuo metodo di azione. Allora qual è il punto di confronto if self.commonSegue == segue {...}nel prepare(for:sender)metodo?
nayem,

@nayem: In prepare(for:sender:), è possibile configurare il controller della vista di destinazione prima che venga visualizzato. Naturalmente puoi anche farlo actionFunction.
jqgsninimo,

@nayem: il motivo per cui lo faccio è cercare di essere coerente con la gestione di altri follower.
jqgsninimo,
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.