Refactorizando

Refactorizando

Introducción

Hace muchos años me gustaba hacer ejemplos en código y hace poco estaba revisando las cosas que tengo en mi GitHub personal y que me encuentro con un proyecto que hice para practicar tres patrones de arquitectura: MVC, MVP y MVVM...

Analizaré un poco mi evolución en casi seis años y, si el tiempo me lo permite, agregaré VIPER. Espero esta refactorización te ayude en tu crecimiento como iOS developer porque al menos a mi me entretiene practicando y resolviendo problemas, hahahahiuahseduiera.

Primeras modificaciones, SWIFT_VERSION

Lo más importante de todo es que el proyecto actualmente no corre, entonces el primer objetivo es hacerlo correr en Xcode 13, lo abrimos y nos encontramos que la versión de Swift no es soportada.

Captura de Pantalla 2021-10-12 a la(s) 20.12.26.png

Actualizaré a la versión mínima soportada por Xcode 13, Swift y de ahí comenzamos a ver que otros errores saca. Captura de Pantalla 2021-10-12 a la(s) 20.22.00.png Y bueno, 43 issues los cuales los podemos categorizar en errores de UIKit y cosas que dejaron de llamarse de alguna manera para llamarse de otra como los colores del sistema de UIColor. Captura de Pantalla 2021-10-12 a la(s) 20.24.11.png Como podemos analizar, al momento de escribir este proyecto era muy reciente el tema de las constraints y, aún las escribí a la antigua. Captura de Pantalla 2021-10-12 a la(s) 20.27.52.png

Constraints y autolayout

Creo que me quise ver intelectual y escribí las constraints una a una, actualmente hay mejores soluciones para dicha implementación como los anchors o directamente storyboards pero, bueno, lo primero es reemplazar las cosas inexistentes como .CenterX o .Equal, entonces cambiemos de esto:

NSLayoutConstraint(item: showGreetingButton,
            attribute: .CenterX,
            relatedBy: .Equal,
            toItem: view,
            attribute: .CenterX,
            multiplier: 1.0,
            constant: 0.0)

a esto:

NSLayoutConstraint(item: showGreetingButton, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0.0)

y luego, a esto 🤭:

showGreetingButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

además de que hice algo raro para activar las constraints:

for con in constraints {
    con.active = true
}

cuando existe el NSLayoutConstraint.activate(constraints). Estos errores son los sencillos de resolver, igual algunos cambios con los botones y sus parámetros; de esto showGreetingButton.setTitle("TAP", forState: .Normal) a esto showGreetingButton.setTitle("TAP", for: .normal) además de que antes los selectores los podías ejecutar con una cadena: showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside) cosa que actualmente tiene que ser con #selector() y... ¡VOILÁ!, logré correr el proyecto en Xcode 13; aún faltan algunas cosas para modificar pero el primero objetivo se logró.

Quitar código duplicado

Otra cosa importante que noté durante el análisis del proyecto es que todos los view controllers son iguales: un botón, una acción y una etiqueta que es modificada al momento de tocar el botón y, específicamente en esta acción es donde se ve la diferencia entre cada uno de los patrones.

.
.
.
// MARK: - Lifecycle methods
override func viewDidLoad() {
    super.viewDidLoad()

    ...

    let button: UIButton = UIButton(type: .system)
    ...

    let label: UILabel = UILabel(frame: .zero)
    ...

    // Layout code
    button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
    ...
}

// MARK: - Private methods
@objc private func didTapButton(_ button: UIButton) {
    ...
}
.
.
.

La solución para evitar este código repetido es crear un controlador del cual hereden el resto de los controladores en cada uno de los patrones y así resolver este problema, ¿o tú que opinas?, ¿hubieras hecho lo mismo?

final class MVCViewController: SharedViewController { }

final class MVPViewController: SharedViewController { }

final class MVVMViewController: SharedViewController { }

What's next?

Es probable que agregue el mismo ejemplo pero con VIPER y una tabla para navegar entre los diferentes patrones, revisa constantemente el repositorio.

Si quieres revisar el proyecto y las modificaciones que hice para que lograra correr puedes checarlo aquí, la refactorización del controlador genérico puedes checarlo aquí; igual si tienes algún comentario ya sabes que con gusto los puedo leer o revisar, también por GitHub en el repositorio, no pasa nada el objetivo es seguir enriqueciendo el conocimiento.

🚀