swift2 ios9 optional-variables

swift2 - Variable global y enlace opcional en Swift



ios9 optional-variables (1)

Comenzaré repitiendo mi comentario de arriba.

Es posible que hayas malinterpretado el concepto de variables globales en Swift.

  1. Si tiene una variable global, no tendrá que "pasarla" entre ninguna vista / método / clase, etc., porque la variable se define en el alcance global (accesible en todas partes).

  2. Generalmente, las variables globales no son una buena idea, y es algo que desea evitar.

En cuanto a la cuestión de las variables globales y rápida, realmente debería incluir singletons en la discusión. Ver, por ejemplo, los siguientes hilos SO existentes:

Comunicación entre TableViewController y ViewController por medio de segues (preparación y desenrollado de los segmentos)

(Esta respuesta terminó siendo muy, y probablemente demasiado minuciosa, ya que no sabía en detalle cuál es su estado actual del programa tableview / viewcontroller. Disculpe la respuesta prolongada y las molestias que esto pueda ocasionar a los lectores) .

Ahora, dejemos las variables globales y analicemos una (entre otras) opciones viables para la comunicación entre los dos controladores en su ejemplo. De su pregunta, resumiré su ejemplo de la siguiente manera

  • VC1 : punto de entrada del guión gráfico, un UITableViewController consiste en UITableViewCell s, donde, en estas celdas, se muestra texto, por ejemplo, a través de instancias de UILabel .
  • VC2 : un UIViewController , accesible desde las celdas de VC1, que contiene una instancia de UITextField . Cuando el usuario ingresa texto en este campo de texto, desea que el texto se muestre en la celda asociada en VC2 (asociado en el sentido de que era la celda en VC1 que se utilizó para acceder a VC2).

TableViewController VC1 y VC2 con las clases (toque de cocoa) TableViewController ( TableViewController.swift ) y ViewController ( ViewController.swift ), respectivamente. Las celdas en el controlador de vista de tabla se asociarán con la clase ( vista de cacao) TableViewCell ( TableViewCell.swift ). Los detalles de estas clases siguen a continuación.

Para este ejemplo simple, tenga en cuenta que no incorporaremos VC1 en un controlador de navegación (que de otra manera es apropiado para la vista de tabla -> ver navegación).

Comenzaremos en el guión gráfico, agregando objetos (arrastrando y soltando desde la biblioteca de objetos) para un Table View Controller y un View Controller . El contenedor de vista de tabla también contendrá automáticamente, en su Table View , una TableViewCell . Continuando en el guión gráfico:

  • Agregue un objeto TableViewCell contenedor TableViewCell en Table View Controller ( TableViewCell como desee)
  • En View Controller , agregue un objeto de Text Field y un objeto de Button (alinéelos como desee).
  • Establezca el punto de entrada al Table View Controller .
  • A continuación, TableViewCell presionada la tecla Ctrl y arrastre un segue ''Mostrar'' desde el TableViewCell al View Controller .
  • Seleccione Show segue y, desde el inspector de atributos, ingrese un identificador para él, por ejemplo, ShowDetail .
  • Finalmente, con TableViewCell seleccionado (como se TableViewCell arriba, desde el inspector de atributos), ingrese un identificador para la celda. Aquí, usaremos simplemente use el identificador TableViewCell .

Ahora dejamos el guión gráfico por ahora e implementamos tres clases, asociadas con el Table View Controller , el View Controller y TableViewCell los formadores.

Comenzamos con el Table View Controller e implementamos nuestra UITableViewController . Tenga en cuenta que aquí, en lugar de usar un NSMutableArray para contener los textos del UITextLabel en cada celda, simplemente usaremos un conjunto de UITextLabel .

// TableViewController.swift Import UIKit class TableViewController: UITableViewController { // Properties var userTextLabels = [String]() var numberOfCells: Int? override func viewDidLoad() { super.viewDidLoad() numberOfCells = loadSampleTextLabels() // Load sample labels. } func loadSampleTextLabels() -> Int { userTextLabels += ["Label #1", "Label #2", "Label #3"] return userTextLabels.count } // func numberOfSectionsInTableView(tableView: UITableView) ... // func tableView(tableView: UITableView, numberOfRowsInSection section: Int) ... override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cellIdentifier = ("TableViewCell") let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TableViewCell // Text for current cell let cellText = userTextLabels[indexPath.row] cell.userSuppliedTextLabel.text = cellText return cell } // ... communication? }

Donde los dos métodos comentados son métodos estándar utilizados en cualquier UITableViewController , para el número de secciones (por ejemplo, return 1 ) y celdas (por ejemplo, return (numberOfCells ?? 0) ) en la tabla, respectivamente. Dejaré de arreglar esto para ti.

Ahora, asociamos los objetos TableViewCell en la vista de tabla con instancias de una subclase a UITableViewCell . Aquí, usaremos una clase muy simple para nuestras células; cada celda contiene una sola instancia de UILabel (creada a través del guión gráfico Ctrl-arrastra como @IBOutlet desde UILabel en las celdas de la vista de tabla).

// TableViewCell.swift import UIKit class TableViewCell: UITableViewCell { // Properties @IBOutlet weak var userSuppliedTextLabel: UILabel! // Ctrl-drag from UILabel (in TableViewCell) in storyboard override func awakeFromNib() { super.awakeFromNib() } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } }

Finalmente, para el controlador de vista al que se accede desde las celdas de vista de tabla: use una sola @IBOutlet para el UITextField utilizado para la entrada de texto de usuario, y maneje los eventos en este campo de texto usando el UITextFieldDelegate preexistente. P.ej:

// ViewController.swift import UIKit class ViewController: UIViewController, UITextFieldDelegate { // Properties @IBOutlet weak var userSuppliedText: UITextField! // Ctrl-drag from storyboard... var cellText: String? override func viewDidLoad() { super.viewDidLoad() userSuppliedText.text = cellText ?? "..." // Handle the user input in the text field through delegate callbacks userSuppliedText.delegate = self } // UITextFieldDelegate func textFieldShouldReturn(textField: UITextField) -> Bool { // User finished typing (hit return): hide the keyboard. textField.resignFirstResponder() return true } func textFieldDidEndEditing(textField: UITextField) { cellText = textField.text } }

También hemos declarado una propiedad de cadena ( cellText ) aquí, que actuará como contenedor para la comunicación entre VC1 y VC2.

Volvemos al guión gráfico y --- desde el inspector de identidad --- asociamos los tres objetos del guión gráfico ( Table View Controller , View Controller , TableViewCell ) con sus clases asociadas que acabamos de escribir.

Ahora estamos casi en nuestra meta; solo resta especificar cómo comunicarse entre los dos controladores.

Comenzaremos con la comunicación de VC1 a VC2. En su comentario anterior, estaba en el camino correcto (para esta solución específica, de todos modos) mirando el prepareForSegue(...) . En la clase para Table View Controller , agregamos el siguiente método:

// ... add to TableViewController.swift override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. if segue.identifier == "ShowDetail" { let viewController = segue.destinationViewController as! ViewController if let selectedCell = sender as? TableViewCell { let indexPath = tableView.indexPathForCell(selectedCell)! let currentTextInCell = userTextLabels[indexPath.row] viewController.cellText = currentTextInCell // <-- note this } } }

Por lo tanto, para la comunicación VC1-> VC2, podemos (en este ejemplo) traer cualquier texto existente que esté ocupando el UILabel en la celda del remitente (como lo especifica la matriz String userTextLabels ). Mire el viewDidLoad(...) en ViewController.swift para ver cómo se pasa este valor desde VC1 y cómo se establece como texto predeterminado en UITextField en VC2.

Ahora, para la comunicación VC2-> VC1, que era la dirección de comunicación específica sobre la que preguntaba, agregue otro método (programáticamente), nuevamente a TableViewController.swift :

// ... add to TableViewController.swift @IBAction func unwindToTableView(sender: UIStoryboardSegue) { if let sourceViewController = sender.sourceViewController as? ViewController, text = sourceViewController.cellText { // ^ note 2nd clause of if let statement above if let selectedIndexPath = tableView.indexPathForSelectedRow { // Update cell text userTextLabels[selectedIndexPath.row] = text tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None) } } }

Aquí, definimos una acción de desenrollado que, cuando se desencadena, recupera la propiedad cellText del controlador de vista que fue el origen del segue, es decir, en nuestro caso, la instancia de ViewController . Pero, ¿cómo desencadenamos esta acción?

Regrese al guión gráfico y al View Controller . Tenga en cuenta los tres pequeños iconos en la parte superior del objeto View Controller , más específicamente, el más derecho de ellos, llamado Exit . Mantenga presionada la tecla Ctrl y arrastre una acción desde su Button hasta el ícono de Exit , y seleccione la unwindToTableView acciones de unwindToTableView . Cuando hace clic en el botón del controlador de vista, la vista se desenrolla (sale) y aterriza en el método unwindToTableView en TableViewController .

La aplicación resultante debería verse más o menos así:

Esto fue mucho más largo de lo que esperaba, pero una vez que empiezas a escribir ... De todos modos, el método anterior no usa, naturalmente, variables globales, pero hace uso de referencias a prepareForSegue futuras ( prepareForSegue ) o históricas ( unwindToTableView ) para obtener ( generalmente desde la vista actual o histórica) o establecer (generalmente en el actual de la vista futura) usando estas referencias (para vista futura / histórica).

Apple tiene su propio tutorial muy completo sobre una aplicación de ejemplo en el contexto tableviewcontroller / viewcontroller que yo recomendaría revisar. Lo encontré muy valioso cuando comencé a programar Swift.

Comience a desarrollar aplicaciones de iOS (Swift)

Tengo algunas dudas bastante simples con respecto a la unión opcional, variable global, envoltura y desenvolver. Como soy nuevo en SWIFT, es muy importante comprender las tetas y los bits de sus conceptos.

1) En Swift si declaro una variable global, tengo 2 opciones para hacerlo opcional o no opcional, así que déjame tener 2-4 o más variables opcionales. Entonces, ¿es recomendable vincular opcionalmente todas esas variables en

viewDidLoad() method// so that I could use them without any problem of unwrapping and fatal error in my program.

2) Permítanme dejarme más claro con el siguiente ejemplo: tengo 2 VC en mi proyecto VC1 y VC2. VC2 tiene un campo de texto en el que el usuario ingresa un valor y lo muestra en una tabla en VC1.

En Vc1

var namevc1 = NSMutableArray?//holds the input of textfield to be passed from VC2.

Como puede ver, mi VC1 es el primer controlador de vista que se carga cuando se ejecuta mi proyecto y estoy usando una variable opcional para llenar mi tabke vuew que es

''arr''

Entonces, cuando la aplicación se ejecuta por primera vez, está vacía. Por lo tanto, podría causar un error fatal al usar su valor en el código. Entonces, ¿cuál es su solución si desvincularlo en el

viewDidLoad()

método o en total declara un tipo de matriz NSMutable vacío en lugar de tipo opcional.

Gracias por adelantado.