Is prepareForSegue forma correcta de pasar valor entre controlleres de vista

Estoy tratando de aprender Swift y estoy tratando de desarrollar la famosa aplicación de notas.

Hay una matriz enlazada a una vista de tabla y otra vista para agregar notas. En el segundo campo de text de vista, el evento de retorno desencadena un segue y vuelve a la vista de tabla.

Quería saber si esta es la manera correcta. Porque de esta manera estoy manipulando una variable en otro controller de vista. No soy un maestro de MVC pero siento que está mal. Aquí está mi fragment de código:

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

Gracias.

Tu pregunta no es realmente acerca de prepareForSegue sino la relación entre los controlleres de vista. La razón por la que su layout "se siente mal" es que lo es. El problema es que su controller de vista de escritura de nota sabe demasiado sobre el controller de vista que lo está utilizando porque está manipulando directamente una variable desde el controller de vista de llamada. Para manipular directamente la variable, debe conocer la class de la persona que llama.

¿Por qué es esto un problema? Hace que su controller de vista de escritura de notas sea less reutilizable. Si escribe correctamente el controller de vista de escritura de nota, podría volver a utilizarlo en otras aplicaciones. Para que sea reutilizable, debe desacoplar el controller de vista de escritura de nota de la persona que llama; no debe saber quién lo llama exactamente.

Entonces, la pregunta es, ¿cómo paso los datos a la persona que llama si no sé quién me llamó? La respuesta es la delegación .

La delegación funciona así:

  1. Usted crea un protocolo que describe un método o methods implementados por el implementador de ese protocolo. En su caso, puede usar un protocolo como NoteWriterDelegate que implementa el método takeNote(note: String) .

     protocol NoteWriterDelegate { func takeNote(note: String) } 

    Defina esto en el file junto con su controller de vista de escritura de notas.

  2. Su networkingactor de notas tendrá un puntero opcional para el delegado:

     weak var delegate: NoteWriterDelegate? 
  3. NoteWriterDelegate declarar su primer controller de vista como NoteWriterDelegate :

     class ViewController: UITableViewController, NoteWriterDelegate 
  4. Y luego implementa el método requerido en tu primer controller de vista:

     func takeNote(note: String) { notes.append(note) } 
  5. Cuando llame a prepareForSegue en preparación para pasar al controller de vista de escritura de notas, se pasará a sí mismo como delegado:

     destinationViewController.delegate = self 
  6. En el controller de vista de escritura de notas, cuando tiene una nota para devolver a la persona que llama, takeNote llamar a takeNote en el delegado:

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

Al hacerlo de esta manera, su networkingactor de notas solo sabe que está hablando con un NoteWriterDelegate . Si desea reutilizar esto en el futuro, simplemente deje caer su class de escritor de notas en otro proyecto, implemente el delegado y funcionará sin que tenga que tocar el código en la class de escritor de notas.

Recomendaría pasar datos a través de prepareForSegue en la mayoría de los casos. Es bastante simple de configurar y fácil de entender.

Sin embargo, recomendaría no actualizar los elementos de la interfaz de usuario (tags, campos de text, etc.) en la vista de destino directamente. En mi opinión, esto es un mal acoplamiento que crea muchos problemas.

En su lugar, cree una propiedad o properties en el controller de vista de destino que la persona que llama puede establecer en prepareForSegue para transferirle datos. Estas deberían ser properties de propósito especial usadas exclusivamente para pasar datos. El controller de vista de destino está entonces a cargo de usar los datos en estas properties para actualizar su UI o estado interno.

La delegación es un enfoque válido, pero me parece que es una exageración para la mayoría de las situaciones. Requiere más configuration y es más abstracto. Esta abstracción no es necesaria en muchas relaciones de controller de vista. Si descubre que necesita volver a usar un controller de vista, siempre podrá refactorizar el uso de delegación más adelante.

No creo que prepareSegue sea la forma ideal de pasar datos entre los controlleres de vista … al less no directamente.

Comparto sus preocupaciones sobre el uso de prepareForSegue para pasar valores entre los controlleres de vista. El controller de vista de origen no debería saber nada sobre el controller de vista de destino (y al revés, en realidad). Idealmente , los controlleres de vista deberían ser islas separadas sin visibilidad entre sí .

Para abordar el acoplamiento que los storyboards parecen alentar, a menudo he usado alguna forma del patrón de mediador para pasar datos entre los controlleres de vista. Aquí hay una muy buena publicación de blog sobre cómo implementar una versión de este patrón alnetworkingedor de storyboards: http://coding.tabasoft.it/ios/mediator-pattern-in-swift/ . Como siempre, este patrón puede no ser el mejor para todas las situaciones, pero creo que ha sido una buena solución en muchos de mis proyectos anteriores.

Básicamente, cómo funcionaría el patrón del mediador dentro del paradigma del guión gráfico es que en el método prepareForSegue del controller de vista, el object segue se pasa al object del mediador. El controller de vista no se preocupa por lo que está dentro o por dónde va la navigation siguiente; solo sabe que no está a la vista. El mediador, que acaba de pasar el object segue (que contiene los controlleres de vista de origen y de destino), es responsable de pasar los datos entre los controlleres de vista de origen y de destino.

Usando este patrón, cada controller de visión felizmente no se da count de la existencia del otro. La class de mediador, por otro lado, debe saber acerca de las relaciones entre los controlleres de visualización (y las interfaces de los controlleres de visualización) en la ruta de navigation. Obviamente, si la navigation cambia, o si los propios controlleres de vista cambian, la class de mediador deberá ajustarse. Sin embargo, cada controller de vista no necesita tener ninguna dependencia mutua y, por lo tanto, no necesita actualizarse para acomodar los cambios en la ruta de navigation o los cambios en los otros controlleres de vista a lo largo de esa ruta de navigation.

No es 'el' path correcto, pero es un path correcto. Especialmente en aplicaciones de storyboard.

Aquí hay una forma alternativa de pasar valor y llamar a la vista.

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