2014-12-13 11 views
6

Sto cercando di imparare Swift e sto cercando di sviluppare la famosa applicazione per le note.È prepareForSegue il modo giusto di passare il valore tra i controller di vista

C'è una matrice associata a una vista tabella e un'altra vista per aggiungere note. Alla seconda vista l'evento textfieldshouldreturn attiva un seguito e torna a tableview.

Volevo sapere se questo è il modo giusto. Perché facendo in questo modo sto manipolando una variabile in un altro controller di vista. Non sono un maestro MVC ma mi sembrava sbagliato. Ecco il mio snippet di codice:

func textFieldShouldReturn(textField: UITextField) -> Bool { 

    self.performSegueWithIdentifier("backSegue", sender: self) 
    return true 
} 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if(segue.identifier == "backSegue"){ 
     let navController = segue.destinationViewController as UINavigationController; 
     let myController = navController.topViewController as NotesTableViewController; 
     if(self.ourTextField?.text != nil || self.ourTextField?.text != ""){ 
      myController.notes.append(self.ourTextField?.text ?? ""); 
     } 

    } 
} 

Grazie.

+0

Perché * senti * è sbagliato? È il modo corretto I controller ara sono usati per gestire i dati e le visualizzazioni di questi dati, quindi quando un push successivo (o pop) un altro viewcontroller è ragionevole passare alcuni dati tra l'origine e la destinazione. –

+0

Questo è sicuramente un modo molto comune di trasmettere dati tra i controller di visualizzazione e non dovresti preoccuparti di usarlo. Un sacco di [sviluppatori ben rispettati] (http://oleb.net/blog/2012/02/passing-data-between-view-controllers/) lo fanno. Non è l'unico vero modo, però, e ci sono altre opzioni. Per quanto ne so, Swift non porta nulla di speciale al tavolo in questo senso, quindi dovresti dare un'occhiata alla [domanda Objective C esistente] (http://stackoverflow.com/questions/5210535/passing-data-b -view-controller), anche. –

risposta

7

La tua domanda non è davvero circa prepareForSegue ma la relazione tra i controller di visualizzazione. La ragione per cui il tuo design "si sente sbagliato" è che lo è. Il problema è che il controller di visualizzazione per la scrittura di note conosce troppo il controller di visualizzazione che lo sta usando perché sta manipolando direttamente una variabile dal controller di visualizzazione chiamante. Per manipolare direttamente la variabile, deve conoscere la classe del chiamante.

Perché questo è un problema? Rende il tuo controller di scrittura delle note meno riutilizzabile. Se scrivi correttamente il controller della vista di scrittura delle note, puoi riutilizzarlo in altre app. Per renderlo riutilizzabile, è necessario disaccoppiare il controllore della vista di scrittura delle note dal chiamante - non deve sapere chi lo sta chiamando esattamente.

Quindi la domanda diventa, come posso trasferire i dati al chiamante se non so chi mi ha chiamato? La risposta è delega.

delegazione funziona così:

  1. Si crea un protocollo che descrive un metodo o metodi che l'implementazioni di tale protocollo realizzerà. Nel tuo caso, potresti utilizzare un protocollo come NoteWriterDelegate che implementa il metodo takeNote(note: String).

    protocol NoteWriterDelegate { 
        func takeNote(note: String) 
    } 
    

    Definire questo nel file insieme al proprio controller di visualizzazione della nota.

  2. tuo scrittore nota avrà un puntatore opzionale al delegato:

    weak var delegate: NoteWriterDelegate? 
    
  3. È necessario dichiarare il vostro primo controller di vista come NoteWriterDelegate:

    class ViewController: UITableViewController, NoteWriterDelegate 
    
  4. e quindi implementare la richiesta metodo nel tuo primo controller di visualizzazione:

    func takeNote(note: String) { 
        notes.append(note) 
    } 
    
  5. Quando si chiama prepareForSegue in preparazione per lo spostamento al la nota scrivendo View Controller, si passa te stesso come il delegato:

    destinationViewController.delegate = self 
    
  6. Nel controller della vista di scrittura nota, quando si dispone di una nota per passare indietro al chiamante, si chiama takeNote sulla delegato:

    delegate?.takeNote(self.ourTextField?.text ?? "") 
    

facendo in questo modo, il vostro scrittore nota sa solo che si sta parlando a NoteWriterDelegate. Se si desidera riutilizzare questo in futuro, basta trascinare la classe del writer di note in un altro progetto, implementare il delegato e funziona senza che si debba toccare il codice nella classe del writer delle note.

2

Raccomanderei di passare i dati tramite prepareForSegue nella maggior parte dei casi. È abbastanza semplice da configurare e facile da capire.

Tuttavia, si consiglia di non aggiornare mai gli elementi dell'interfaccia utente (etichette, campi di testo e così via) direttamente nella vista di destinazione. Secondo me, questo è un cattivo accoppiamento che crea molti problemi.

Invece, creare una proprietà o proprietà sul controller della vista di destinazione che il chiamante può impostare in prepareForSegue per passare i dati ad esso. Queste dovrebbero essere proprietà di scopo speciale utilizzate esclusivamente per il trasferimento di dati. Il controller della vista di destinazione è quindi responsabile dell'utilizzo dei dati in queste proprietà per aggiornare l'interfaccia utente o lo stato interno.

La delega è un approccio valido, ma trovo eccessivo per la maggior parte delle situazioni. Richiede più setup ed è più astratto. Questa astrazione non è necessaria in molte relazioni tra i controller di visualizzazione. Se scopri che è necessario riutilizzare un controller di visualizzazione, puoi sempre refactoring per utilizzare la delega in un secondo momento.

2

Non credo che prepareSegue sia il modo ideale per passare i dati tra i controller di visualizzazione ... almeno non direttamente.

Condivido le vostre preoccupazioni sull'utilizzo di prepareForSegue per passare i valori tra i controller di visualizzazione. Il controller della vista sorgente non dovrebbe sapere nulla sul controller della vista di destinazione (e viceversa, se è per questo). Idealmente i controller di vista dovrebbero essere isole separate senza visibilità l'uno nell'altro.

Per affrontare l'accoppiamento che gli storyboard sembrano incoraggiare, ho spesso utilizzato alcune forme di mediator pattern per passare i dati tra i controller di visualizzazione. Ecco un post del blog piuttosto buono su come implementare una versione di questo pattern attorno agli storyboard: http://coding.tabasoft.it/ios/mediator-pattern-in-swift/. Come sempre, questo modello potrebbe non essere la soluzione migliore per tutte le situazioni, ma ritengo che sia stata una buona soluzione in molti dei miei progetti passati.

In sostanza, il modo in cui il modello di mediatore funzionerebbe all'interno del paradigma dello storyboard è che in ogni metodo prepareForSegue del controller di visualizzazione, l'oggetto segue viene passato all'oggetto mediatore. Il controller della vista non si cura di cosa c'è dentro o dove sta andando la navigazione successiva; sa solo che sta per non essere visibile. Il mediatore, che ha appena passato l'oggetto segue (contenente i controller di visualizzazione di origine e di destinazione), è quindi responsabile del trasferimento dei dati tra i controller di visualizzazione di origine e di destinazione.

Utilizzando questo modello, ciascun controller di visualizzazione è beatamente inconsapevole dell'esistenza dell'altro. La classe mediatore, d'altra parte, deve conoscere le relazioni tra i controller della vista (e le interfacce dei controllori della vista) nel percorso di navigazione. Ovviamente se la navigazione cambia o se i controller della vista cambiano, la classe del mediatore dovrà essere aggiustata. Tuttavia, ciascun controller di visualizzazione non deve necessariamente dipendere l'uno dall'altro e pertanto non è necessario aggiornarlo per adattarsi alle modifiche nel percorso di navigazione o alle altre unità di controllo della vista lungo tale percorso di navigazione.

0

Non è "la" via giusta, ma è la strada giusta. Soprattutto nelle applicazioni storyboard.

Ecco un modo alternativo di passare il valore e chiamare la vista.

var myNewVC = NewViewController() 
myNewVC.data = self 
navigationController?.presentViewController(myNewVC, animated: true, completion: nil) 
Problemi correlati