Patrones de diseño en Swift: nivel avanzado con ejemplos para iOS/macOS
\n\nLos patrones de diseño son soluciones probadas para problemas típicos en el desarrollo. Para los desarrolladores de Swift que trabajan en aplicaciones iOS y macOS, dominar los patrones avanzados es fundamental para crear proyectos escalables, comprobables y mantenibles. En este artículo, analizaremos cuatro patrones clave: MVVM, Coordinator, Builder y Factory. Cada uno resuelve problemas arquitectónicos específicos y se utiliza activamente en el desarrollo comercial.
\n\n1. Patrón MVVM (Model-View-ViewModel) en Swift
\n\nMVVM es uno de los patrones arquitectónicos más populares para SwiftUI y UIKit. Proporciona una separación clara entre la lógica de presentación y la lógica de negocio, lo que facilita las pruebas y la reutilización del código.
\n\nComponentes de MVVM:
\n- \n
- Model — datos y lógica de negocio (solicitudes de red, trabajo con BD). \n
- View — UI (SwiftUI View o UIViewController). \n
- ViewModel — intermediario que prepara los datos para la View y maneja las acciones del usuario. \n
Ejemplo de implementación en SwiftUI:
\n\nimport SwiftUI\nimport Combine\n\n// MARK: - Model\nstruct User: Codable {\n let id: Int\n let name: String\n let email: String\n}\n\n// MARK: - ViewModel\nclass UserViewModel: ObservableObject {\n @Published var users: [User] = []\n @Published var isLoading = false\n private var cancellables = Set<AnyCancellable>()\n \n func fetchUsers() {\n isLoading = true\n guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { return }\n \n URLSession.shared.dataTaskPublisher(for: url)\n .map { $0.data }\n .decode(type: [User].self, decoder: JSONDecoder())\n .receive(on: DispatchQueue.main)\n .sink(receiveCompletion: { [weak self] completion in\n self?.isLoading = false\n if case .failure(let error) = completion {\n print("Error: \\(error)")\n }\n }, receiveValue: { [weak self] users in\n self?.users = users\n })\n .store(in: &cancellables)\n }\n}\n\n// MARK: - View\nstruct UserListView: View {\n @StateObject private var viewModel = UserViewModel()\n \n var body: some View {\n NavigationView {\n List(viewModel.users, id: \\.id) { user in\n VStack(alignment: .leading) {\n Text(user.name).font(.headline)\n Text(user.email).font(.subheadline).foregroundColor(.secondary)\n }\n }\n .navigationTitle("Users")\n .overlay {\n if viewModel.isLoading {\n ProgressView()\n }\n }\n }\n .onAppear {\n viewModel.fetchUsers()\n }\n }\n}\n\nVentajas de MVVM:
\n- \n
- Separación clara de responsabilidades. \n
- Pruebas sencillas del ViewModel sin UI. \n
- Actualización reactiva de la UI mediante Combine o @Published. \n
2. Patrón Coordinator (Coordinador) para navegación
\n\nCoordinator resuelve el problema de los ViewControllers "gordos", trasladando la lógica de navegación a objetos separados. Esto simplifica la reutilización de pantallas y hace que la navegación sea flexible.
\n\nEstructura:
\n- \n
- AppCoordinator — coordinador principal que gestiona los hijos. \n
- ChildCoordinator — responsable de un flujo específico (por ejemplo, autenticación o pantalla principal). \n
Ejemplo de implementación para UIKit:
\n\nimport UIKit\n\n// MARK: - Coordinator Protocol\nprotocol Coord