Contenedor de Inyección de Dependencias para Swift (iOS/macOS): Swinject

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

Swinject — Contenedor de Inyección de Dependencias para Swift (iOS/macOS)



La Inyección de Dependencias (DI) es uno de los principios clave de SOLID, que permite crear código débilmente acoplado, testeable y escalable. En el mundo de Swift para desarrollo iOS y macOS, una de las bibliotecas más populares que implementa DI es Swinject. Es un contenedor de inyección de dependencias ligero pero potente que simplifica la gestión de objetos y su ciclo de vida.



En este artículo, analizaremos en detalle cómo funciona Swinject, cómo instalarlo y usarlo en proyectos reales.



¿Qué es la Inyección de Dependencias y para qué sirve un contenedor?

La inyección de dependencias es una técnica en la que un objeto recibe sus dependencias desde el exterior, en lugar de crearlas él mismo. Esto aumenta la flexibilidad y simplifica las pruebas. Un contenedor DI (por ejemplo, Swinject) automatiza el proceso de creación y vinculación de objetos, liberando al desarrollador de escribir código repetitivo.



Instalación de Swinject

Swinject se puede instalar usando Swift Package Manager, CocoaPods o Carthage. Veamos el método más moderno: SPM:



// En Xcode: File → Swift Packages → Add Package Dependency// URL: https://github.com/Swinject/Swinject.git// Versión: desde 2.8.0 en adelante


O agréguelo en Package.swift:

dependencies: [    .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0")]


Componentes principales de Swinject

  • Container — el objeto principal donde se registran y resuelven las dependencias.
  • Service — el tipo (protocolo o clase) que queremos inyectar.
  • Registration — el proceso de vincular una abstracción (protocolo) con una implementación concreta.
  • Scope — gestiona el ciclo de vida del objeto (transitorio, singleton, etc.).


Ejemplo básico de uso

Supongamos que tenemos un protocolo NetworkServiceProtocol y su implementación NetworkService:



import Swinject

protocol NetworkServiceProtocol { func fetchData() -> String}

class NetworkService: NetworkServiceProtocol { func fetchData() -> String { return "Datos obtenidos" }}

// Creamos el contenedorlet container = Container()

// Registramos la dependenciacontainer.register(NetworkServiceProtocol.self) { _ in NetworkService() }

// Resolvemos (obtenemos) la instancialet service = container.resolve(NetworkServiceProtocol.self)!print(service.fetchData()) // "Datos obtenidos"


Inyección de dependencias en ViewController (iOS)

Más a menudo, Swinject se usa para inyectar servicios en los controladores. Veamos un ejemplo con un view model:



import Swinject

// Protocolo e implementación del view modelprotocol UserViewModelProtocol { func getUsers() -> [String]}

class UserViewModel: UserViewModelProtocol { private let networkService: NetworkServiceProtocol init(networkService: NetworkServiceProtocol) { self.networkService = networkService } func getUsers() -> [String] { // Usamos networkService para cargar return ["Alice", "Bob"] }}

// Registro en el contenedorcontainer.register(UserViewModelProtocol.self) { resolver in let network = resolver.resolve(NetworkServiceProtocol.self)! return UserViewModel(networkService: network)}

// Uso en el controladorclass UsersViewController: UIViewController { var viewModel: UserViewModelProtocol? override func viewDidLoad() { super.viewDidLoad() viewModel = container.resolve(UserViewModelProtocol.self) print(viewModel?.getUsers() ?? []) }}


Ciclos de vida de objetos (Scopes)

Swinject admite varios scopes:

  • .transient — se crea una nueva instancia cada vez que se resuelve.
  • .container — el objeto se comporta como un singleton dentro del contenedor.
  • .graph — la instancia se comparte dentro de un grafo de resolución.


Ejemplo de uso de scopes:

container.register(NetworkServiceProtocol.self) { _ in NetworkService() }    .inObjectScope(.container) // Singleton dentro del contenedor


Conclusión

Swinject simplifica enormemente la gestión de dependencias en proyectos Swift. Proporciona una API limpia, soporta varios scopes y se integra fácilmente con el ecosistema de Apple. Si aún no lo ha probado, ¡pruébelo en su próximo proyecto!

Recommendations