Diseño de software

¿Cuándo introducir un contenedor DI? Resumen de Swinject y Factory

Al desarrollar para iOS, llega un momento en que surge esta pregunta.

4 min de lectura
Imagen de portada de ¿Cuándo introducir un contenedor DI? Resumen de Swinject y Factory

Al desarrollar para iOS, llega un momento en que surge esta pregunta.

«Esto puedo pasarlo por el constructor; ¿de verdad necesito usar también un contenedor DI?»

Cuando un proyecto personal crece, todos nos enfrentamos alguna vez a esta duda. Probé Swinject y Factory en proyectos reales y establecí un criterio.

Voy directamente a la conclusión.

Si tienes menos de 20 pantallas, la inyección por constructor es suficiente sin un contenedor DI.

El momento de introducirlo llega cuando el grafo de dependencias se complica y sustituyes mocks de prueba con frecuencia.

Y si lo introduces, elige Factory.

Explicaré cuándo introducirlo y por qué elegir Factory, siguiendo el orden de mi experiencia.

Antes de introducir un contenedor DI, comprueba esto

Empecemos por aclarar lo que suele confundirse.

La inyección de dependencias (DI) y el contenedor DI son cosas distintas.

La inyección de dependencias es el hábito de diseño de proporcionar desde fuera los objetos necesarios. No requiere ninguna biblioteca.

// Esto también es una excelente inyección de dependencias
final class LoginViewModel {
    private let authService: AuthService
    init(authService: AuthService) {
        self.authService = authService
    }
}

En cambio, un contenedor DI es una herramienta que gestiona en un solo lugar dónde y cómo crear esos objetos.

Si la inyección por constructor basta, todavía es pronto para un contenedor.

Estos son los indicios que uso para decidir introducirlo.

  1. Cuando el código de inicialización se repite en cada pantalla y empieza a resultar pesado pasar objetos
  2. Cuando sustituyes con frecuencia objetos reales por objetos falsos en las pruebas
  3. Cuando varias partes de la aplicación deben compartir la misma instancia (con carácter de singleton)
  4. Cuando el equipo crece y preguntas a menudo «¿dónde se crea este objeto?»

Si se cumplen dos o más, empiezo a considerar un contenedor.


¿Qué diferencia hay entre Swinject y Factory?

Swinject es el contenedor de tiempo de ejecución tradicional del ecosistema Swift, usado desde 2015. Se registra en Container y se obtiene mediante resolve. El problema es que resolve devuelve un opcional. Si olvidas registrarlo, la compilación pasa correctamente y la aplicación solo falla al forzar el desempaquetado de nil en esa pantalla.

Factory nació para corregir precisamente estas limitaciones de los contenedores tradicionales. Michael Long, creador de Resolver, lo rediseñó basándose en esa experiencia. La idea clave es que «la definición es el registro». Como las fábricas se definen como propiedades del contenedor, no existe el concepto de olvidar registrarlas. Una referencia incorrecta produce un error en compilación, no en tiempo de ejecución.

Esta tabla resume las diferencias que he percibido hasta 2026.

Elemento Swinject Factory
Forma de registrar y resolver resolve en tiempo de ejecución (devuelve un opcional) Definición basada en tipos + envoltorio de propiedad
Si falta un registro nil o fallo en tiempo de ejecución Bloqueo previo mediante error de compilación
Gestión de ámbitos Compatible Compatible (.singleton, .cached, .shared, etc.)
Dependencias externas Dependencia de un framework adicional Paquete único y ligero
Curva de aprendizaje Algo pronunciada Más gradual

Antes se aconsejaba «Swinject si necesitas una gestión compleja de ámbitos», pero ya no. Factory también admite singleton, caché y ámbitos compartidos. Factory hace de forma más segura lo que hacía Swinject.

Al probarlo, descubrí que Factory puede empezar con un solo archivo
Al probarlo, descubrí que Factory puede empezar con un solo archivo

Por eso la conclusión es Factory

Estos fueron mis criterios concretos para decidir.

Si lo introduces desde cero, Factory es suficiente

Tanto en proyectos individuales como de equipo, Factory resultó poco exigente porque permite empezar con un solo paquete y sin dependencias externas. Lo decisivo fue que los fallos en tiempo de ejecución por olvidar un registro desaparecen estructuralmente.

// Factory: La definición es el registro
extension Container {
    var authService: Factory<AuthService> {
        self { LiveAuthService() }.singleton  // El ámbito también cabe en una línea
    }
}
// Lado consumidor
@Injected(\.authService) private var authService

Sustituirlo por un mock en las pruebas también requiere una sola línea.

Container.shared.authService.register { MockAuthService() }

¿Cuándo conservar Swinject?

Al mantener una base de código grande construida con Swinject. No hay motivo para retirar de inmediato una estructura de assembly que funciona bien. Aun así, cada vez más equipos migran gradualmente a Factory empezando por los módulos nuevos. Para una adopción nueva, ya es difícil encontrar razones para elegir Swinject.


Preguntas frecuentes (Q&A)

P. ¿No puedo empezar con un contenedor desde el principio?

No te lo desaconsejo tajantemente, pero no lo recomiendo. Cuando el grafo de dependencias es simple, el contenedor añade otra capa de ocultación y dificulta el seguimiento del código.

P. ¿Puedo pasar de Swinject a Factory?

Sí. Una migración gradual por módulos, manteniendo ambos contenedores durante un tiempo, es lo más realista. Requiere revisar los puntos de registro y la configuración de ámbitos, por lo que puede tardar en proyectos grandes; después desaparece la preocupación por los fallos en tiempo de ejecución.

P. ¿Cuál conviene en un proyecto SwiftUI?

Sin duda, Factory. Al basarse en envoltorios de propiedad, encaja naturalmente con el estilo declarativo de SwiftUI, y colocar un mock en una vista previa es sencillo.


Lo más limpio es introducir un contenedor DI cuando realmente se necesita.

Si decides introducirlo, elige Factory sin darle más vueltas. Nació para corregir las limitaciones de los contenedores existentes, así que sirve tanto para empezar pequeño como para crecer. Cuenta cuántos de los cuatro indicios anteriores se cumplen ahora.