Transferencia de datos entre pantallas en iOS: de principiante a profesional
\n\nCualquiera que haya empezado a programar para iOS, tarde o temprano se ha topado con un muro: "¿Cómo paso una cadena, un array o un objeto a otra pantalla?". La pregunta es tan popular que en Stack Overflow ha acumulado miles de visitas y decenas de respuestas. Y no es casualidad: la arquitectura de iOS está diseñada de forma que cada pantalla (ViewController) vive su propia vida, y los datos entre ellas deben transferirse de manera consciente.
\n\nEn este artículo analizaremos 5 métodos principales para transferir datos entre view controllers en Swift. Aprenderá cuándo usar segue, y cuándo usar delegados o closures, y por qué NotificationCenter no siempre es malo. ¡Allá vamos!
\n\n¿Por qué es esto un problema?
\niOS utiliza una arquitectura MVC (Model-View-Controller) estricta. Cada ViewController es responsable de su propia parte de la pantalla y no tiene acceso directo a los datos del controlador vecino. Esto se hace por seguridad y modularidad, pero para el desarrollador significa que debe "pasar" explícitamente los datos del punto A al punto B.
\n\nImagine: tiene una lista de usuarios y quiere mostrar información detallada al pulsar sobre una celda. Pulsa — se abre una nueva pantalla. ¿Cómo pasar el ID del usuario? Aquí es donde comienza la magia.
\n\nMétodo 1: Transferencia de datos mediante Storyboard Segue (el más sencillo)
\nLa forma más directa es usar prepare(for:sender:). Simplemente prepara los datos antes de la transición. Ideal para aplicaciones simples y prototipos.
// En el ViewController de origen\noverride func prepare(for segue: UIStoryboardSegue, sender: Any?) {\n if segue.identifier == "showDetail" {\n guard let destinationVC = segue.destination as? DetailViewController else { return }\n destinationVC.userID = 42 // pasamos un número\n destinationVC.userName = "Ana" // pasamos una cadena\n }\n}\n\n// En DetailViewController\nvar userID: Int = 0\nvar userName: String = ""\n\n\nVentajas: Mínimo código, todo en un solo lugar. Desventajas: Fuerte acoplamiento al Storyboard, difícil de probar, fácil confundirse con los identificadores.
\n\nMétodo 2: Navegación programática con transferencia de datos (nivel avanzado)
\nCuando se cansa de los segues y quiere controlar todo desde el código, use una instancia directa del controlador.
\n\n// En el ViewController de origen\nfunc showDetail() {\n let storyboard = UIStoryboard(name: "Main", bundle: nil)\n guard let detailVC = storyboard.instantiateViewController(withIdentifier: "DetailVC") as? DetailViewController else { return }\n \n detailVC.userID = 42\n detailVC.userName = "Ana"\n \n navigationController?.pushViewController(detailVC, animated: true)\n}\n\n\nEste método ofrece control total: puede cargar datos de la red, verificarlos y solo entonces hacer la transición. Excelente para lógica compleja.
\n\nMétodo 3: Delegados (Delegate Pattern) — comunicación de retorno
\n¿Qué hacer si necesita pasar datos de vuelta? Por ejemplo, el usuario seleccionó una fecha en la segunda pantalla y queremos devolverla a la primera. Aquí es donde el delegado viene al rescate.
\n\nPaso 1: Crear el protocolo
\nprotocol DatePickerDelegate: AnyObject {\n func didSelectDate(_ date: Date)\n}\n\n\nPaso 2: Agregar el delegado en el controlador hijo
\nclass DatePickerViewController: UIViewController {\n weak var delegate: DatePickerDelegate?\n \n @IBAction func saveButtonTapped(_ sender: UIButton) {\n let selectedDate = datePicker.date\n delegate?.didSelectDate(selectedDate)\n dismiss(animated: true)\n }\n}\n\n\nPaso 3: Implementar el delegado en el controlador padre
\nclass MainViewController: UIViewController, DatePickerDelegate {\n func didSelectDate(_ date: Date) {\n print("Fecha recibida: \\(date)")\n // actualizamos la UI\n }\n \n override f