Principios SOLID en Swift: teoría y práctica para desarrolladores iOS avanzados

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Por qué SOLID es importante para el desarrollador de Swift

En el mundo del desarrollo iOS, crear código mantenible y escalable es una tarea clave. Los principios SOLID, formulados por Robert Martin, siguen siendo el estándar de oro de la arquitectura de software. A nivel avanzado, el dominio de estos principios en Swift permite no solo escribir código limpio, sino también construir sistemas flexibles y resistentes a los cambios de requisitos. En este artículo, analizaremos cada principio con ejemplos en Swift, enfocándonos en problemas reales del desarrollador iOS/macOS.



1. Principio de Responsabilidad Única (SRP) en Swift

Teoría: Cada clase o estructura debe tener una sola razón para cambiar. En la práctica, esto significa que un módulo se encarga de una tarea claramente definida.



Problema: ViewController sobrecargado

En UIKit, es común encontrar controladores que gestionan la UI, procesan solicitudes de red y guardan datos al mismo tiempo. Esto viola el SRP.

// ❌ Violación de SRPclass UserViewController: UIViewController {    @IBOutlet weak var tableView: UITableView!    private var users: [User] = []

override func viewDidLoad() { super.viewDidLoad() fetchUsers() }

private func fetchUsers() { // Solicitud de red URLSession.shared.dataTask(with: URL(string: "https://api.example.com/users")!) { data, _, _ in // Parseo de JSON // Guardado en Core Data DispatchQueue.main.async { self.tableView.reloadData() } }.resume() }}


Solución: separación de responsabilidades

Extraemos la gestión de datos y red a servicios separados.

// ✅ SRP: servicio separado para trabajar con usuariosprotocol UserServiceProtocol {    func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void)}

class UserService: UserServiceProtocol { func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void) { // Lógica de solicitud de red }}

// ✅ SRP: gestor separado para Core Dataclass CoreDataManager { func saveUsers(_ users: [User]) { // Guardado en Core Data }}

// ✅ SRP: ViewController solo gestiona la UIclass UserViewController: UIViewController { private let userService: UserServiceProtocol private let coreDataManager: CoreDataManager

init(userService: UserServiceProtocol, coreDataManager: CoreDataManager) { self.userService = userService self.coreDataManager = coreDataManager super.init(nibName: nil, bundle: nil) }

override func viewDidLoad() { super.viewDidLoad() loadUsers() }

private func loadUsers() { userService.fetchUsers { [weak self] result in switch result { case .success(let users): self?.coreDataManager.saveUsers(users) self?.updateUI(with: users) case .failure(let error): self?.showError(error) } } }}


2. Principio Abierto/Cerrado (OCP) y protocolos en Swift

Teoría: Las entidades de software (clases, módulos) deben estar abiertas para extensión, pero cerradas para modificación. En Swift, esto se logra mediante protocolos y herencia.



Ejemplo: sistema de notificaciones

// ❌ Violación de OCP: al agregar un nuevo tipo de notificación, hay que modificar el switchclass NotificationSender {    func send(_ notification: Notification, type: String) {        switch type {        case "email":            // Envío de email        case "push":            // Envío de push        default:            break        }    }}

// ✅ OCP: usamos un protocoloprotocol NotificationChannel { func send(_ notification: Notification)}

class EmailChannel: NotificationChannel { func send(_ notification: Notification)

Blogs

Book Recommendations