Está en la página 1de 11

12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

SwiftBeta
Latest Apple Watch Apps Arquitecturas CallKit Combine Command Line Tool
El Libro de Swift Firebase Git Newsletter Patrones Peticiones HTTP Playgrounds Soft Skills
SPM Swift SwiftUI SwiftUI Intermedio Testing Threads Tools UIKit Vapor Vision Pro
VisionKit WWDC22 WWDC23 Xcode

Aprende a usar los Coordinators en la Arquitectura Model View Controller

Aprende a usar la Arquitectura


Model-View-Controller con
Coordinators en Swift
Al usar arquitecturas podemos aplicar diferentes patrones. En este
ejemplo vamos a usar el Patrón Coordinator dentro de la arquitectura
Model View Controller en Swift. Este patrón¡Suscríbete
nos permitea encapsular
SwiftBeta GRATIS la!
💎
lógica de navegación dentro de una clase que solo tiene esta
responsabilidad
https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 1/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

SwiftBeta
2 ene. 2023
...

👇 SÍGUEME PARA APRENDER SWIFTUI, SWIFT, XCODE, etc 👇

▶️¡Suscríbete al canal!
🤩 ¡Sígueme en Twitter!
📙 COMPRAR EL LIBRO DE SWIFT ⭐️

Patrón Coordinator en la Arquitectura Model View Controller

Hoy en SwiftBeta vamos a aprender a añadir Coordinators dentro de la


Arquitectura Model-View-Controller. Lo que vimos en el anterior video fue la
https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 2/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

arquitectura Model-View-Controller, donde creábamos una app desde cero.


Esta app realizaba una petición HTTP a la API de rick and morty, y también
realizaba una navegación al pulsar uno de los personajes en la lista. Esta nueva
vista mostraba información de detalle del personaje seleccionado. Todo esto lo
hicimos siguiendo la arquitectura Model-View-Controller, una arquitectura muy
usada dentro del mundo iOS.
Al finalizar el anterior video, navegábamos de un ViewController a otro, y esta
lógica de navegación la teníamos dentro del ViewController inicial (Esta que os
estoy mostrando ahora mismo). Sabíamos exactamente qué celda del
UITableView se había pulsado, y en base a esa información recuperábamos el
modelo y se lo pasábamos al ViewController que se iba a mostrar. Pues bien,
poara poder desacoplar esta lógica vamos a usar un patrón muy usado en
aplicaciones móviles llamado Coordinators. De esta manera crearemos un
componente nuevo que sabrá como manejar la navegación dentro de nuestra
app, quitándole esta responsabilidad al ViewController.
Esto tiene muchas ventajas, desde el desacople de lógica, poder reutilizar
navegaciones en otras partes de tu app, crear multiples navegaciones push o
modales, etc.

Coordinators
Vamos a continuar con nuestro proyecto, el que vimos en el anterior video.
Los coordinators son muy sencillos de implementar, y hoy vamos a ver un
ejemplo muy básico pero potente. Lo que vamos hacer es crear una carpeta
llamada Coordinators, y dentro de ella vamos a crear un fichero nuevo que
tendrá el siguiente protocolo:
import Foundation
import UIKit

protocol Coordinator {
var viewController: UIViewController? { get }
https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 3/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

var navigationController: UINavigationController? { get }

func start()
}

extension Coordinator {
var viewController: UIViewController? { nil }
var navigationController: UINavigationController? { nil }
}

Protocolo Coordinator que conformaremos en todos nuestro Coordinators

Lo único que he hecho ha sido crear un protocolo llamado Coordinator. Este


protocolo tiene dos variables opcionales llamadas viewController y
navigationController. Estas variables nos servirán para hacer un present en el
caso de querer presentar de forma modal un ViewController. O un push en el
caso de presentar un ViewController cuando usamos un NavigationController.
También, hay un método llamado start que es el que lanzará la acción de
navegar. Todo esto lo vamos a implementar ahora en un MainCoordinator.
Para finalizar, he añadido un valor por defecto de nil a las variables del
protocolo Coordinator.

MainCoordinator
Lo que vamos a crear ahora es un MainCoordinator. Es muy interesante por que
lo vamos a llamar cuando se ejecute nuestra app.
import Foundation
import UIKit

class MainCoordinator: Coordinator {


var navigationController: UINavigationController?

init(navigationController: UINavigationController) {

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 4/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

self.navigationController = navigationController
}
// code...
}

Primer coordinator de nuestra app llamado MainCoordinator

Al crear nuestro MainCoordinator, hacemos que conforme nuestro protocolo


Coordinator. En este caso vamos a inicializarlo con un NavigationController que
le inyectaremos cuando lo inicialicemos desde el SceneDelegate en los
siguientes minutos.
Para acabar de conformar el protocolo Coordinator, necesitamos implementar
el método start(), pues vamos a ello:
func start() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let listOfCharactersViewController = storyboard.instantiateViewCon
navigationController?.pushViewController(listOfCharactersViewContr
}

Creamos la implementación del método start que será el encargado de realizar la navegación

Al cargar nuestro ViewController desde el Storyboard (Como vimos en el video


sobre Storyboards y XIBs), necesitamos instanciar
CharactersListViewController de esa manera.
Una vez tenemos esta parte listada, tenemos que ir a nuestro punto de entrada
de la app:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 5/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

var mainCoordinator: MainCoordinator?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession

guard let scene = (scene as? UIWindowScene) else { return }

window = UIWindow(windowScene: scene)


let navigationController = UINavigationController()
mainCoordinator = MainCoordinator(navigationController: naviga
mainCoordinator?.start()

window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}
}

Añadimos nuestro MainCoordinator en el punto de entrada de nuestra app

Ahora ya estamos listos para utilizar nuestro MainCoordinator, si compilamos


vamos a ver qué ocurre. Obtenemos un crash, eso es porque nos hemos dejado
un paso, hay que añadir el identificador del view controller en el Storyboard, de
esta manera podemos instanciar correctamente el ViewController
CharactersListViewController (esto también lo vimos en el video de
Storyboards)

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 6/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

Añadimos un Storyboard ID para que funcione la instancia de nuestro ViewController

Una vez añadido el Storyboard ID, vamos a volver a compilar.


Perfecto, hemos creado nuestro primer Coordinator.

PushCoordinator
Ahora vamos a añadir otro ViewController, vamos a crear una nueva clase
llamada CharacterDetailPushCoordinator
import Foundation
import UIKit

final class CharacterDetailPushCoordinator: Coordinator {


let characterModel: CharacterModel
var navigationController: UINavigationController?

init(characterModel: CharacterModel, navigationController: UINavig


self.characterModel = characterModel
self.navigationController = navigationController
}

func start() {

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 7/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

let characterDetailViewController = CharacterDetailViewControl


self.navigationController?.pushViewController(characterDetailV
}
}

Creamos un Coordinator para hacer push desde un UINavigationController

Esta clase tiene lo necesario para realizar la navegación que estábamos


haciendo para poder navegar al CharacterDetail. Vamos a crear una instancia
de esta nueva clase en nuestro ViewController:
Creamos la propiedad:
var characterDetailCoordinator: CharacterDetailPushCoordinator?

Creamos una propiedad de nuestro Coordinator en el ViewController

Y ahora sustituimos el código de navegación que estaba directamente en el


ViewController:
tableViewDelegate?.didTapOnCell = { [weak self] index in
print("Index \(index)")
// Present New View Controller
guard let dataSource = self?.tableViewDataSource else {
return
}
let characterModel = dataSource.characters[index]
self?.characterDetailCoordinator = CharacterDetailPushCoordinator(
n
self?.characterDetailCoordinator?.start()
}

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 8/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

Sustituimos la lógica que había en nuestro ViewController por nuestro Coordinator

Si compilamos vemos que funciona perfectamente, y que hemos movido la


responsabilidad de la navegación a otra clase. A otra clase que su única
responsabilidad es esa, la navegación.

ModalCoordinator
Imagina si es potente, que si ahora queremos presentar modalmente el
CharacterDetail, podemos crear el siguiente Coordinator, lo vamos a llamar
CharacterDetailModalCoordinator
import Foundation
import UIKit

final class CharacterDetailModalCoordinator: Coordinator {


let characterModel: CharacterModel
var viewController: UIViewController?

init(characterModel: CharacterModel, viewController: UIViewControl


self.characterModel = characterModel
self.viewController = viewController
}

func start() {
let characterDetailViewController = CharacterDetailViewControl
viewController?.present(characterDetailViewController, animate
}
}

Creamos un nuevo Coordinator para realizar la navegación de forma Modal

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 9/14
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

Y lo único que tendríamos que hacer en nuestro ViewController es crear la


propiedad:
var characterDetailCoordinator: CharacterDetailModalCoordinator?

Creamos una instancia en nuestro ViewController

Y cambiar el PushCoordinator que teníamos, por el nuevo que acabamos de


crear:
tableViewDelegate?.didTapOnCell = { [weak self] index in
print("Index \(index)")
// Present New View Controller
guard let dataSource = self?.tableViewDataSource else {
return
}
let characterModel = dataSource.characters[index]
self.characterDetailCoordinator = CharacterDetailModalCoordinator(
v
self.characterDetailCoordinator?.start()
}

Usamos nuestro nuevo Coordinator para presentar el ViewController de forma Modal

No hemos tenido que modificar lógica en nuestro ViewController, ya que hemos


creado una ModalCoordinator que se encarga de presentar el ViewController.
Si compilamos, vemos que ahora al pulsar una celda, se presenta modalmente
el CharacterDetailViewController.

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 10/14
Inyectar dependencias en el
12/15/23, 7:27 PM Aprende a usar la Arquitectura Model-View-Controller con Coordinators en Swift

CharactersListViewController
Quizás es pronto para hablar de esto, pero voy a empezar a introducirlo. A mi
me encanta sacar responsabilidades en clases, y que estas clases conformen
un protocolo, una interfaz o también lo puedes llamar contrato. De esta
manera, al crear los tests es muy fácil mockear (ojo que esto es un término
nuevo que aún no había sacado en el canal).
En el caso de la vistas, están en una clase aparte y podríamos hacer snapshots
tests directamente usando CharactersListView o CharacterDetailView (esto lo
veremos en próximos videos).
En CharactersListViewController podríamos dejar de usar el Storyboard, e
instanciar el ViewController con un init todas sus propiedades, de esta manera
podríamos inyectar mocks para nuestros tests. Pero no te preocupes, que esto
lo veremos en otros videos.

Conclusión
Hoy hemos aprendido a cómo usar el Patrón Coordinator dentro de la
arquitectura Model-View-Controller. Este Patrón nos permite extraer la
responsabilidad de navegación que añadiamos en nuestro ViewController para
navegar a otro. Esta responsabilidad está encapsulada dentro de un
Coordinator que se encarga de navegar a otras pantallas.
TE PODRÍA INTERESAR

https://www.swiftbeta.com/arquitectura-model-view-controller-con-coordinators-en-swift/ 11/14

También podría gustarte