Diseño de software

Inyección en Swift: constructor, propiedad o método

Al crear apps iOS con Swift, tarde o temprano surge esta duda.

4 min de lectura
Imagen de portada de Inyección en Swift: constructor, propiedad o método

Al crear apps iOS con Swift, tarde o temprano surge esta duda.

«¿Qué forma de inyección de dependencias debería usar?»

Empecemos por la conclusión.

Salvo que haya un motivo concreto, la inyección por constructor (init) es la opción más cercana a la correcta.

Explicaré por qué y cuándo conviene usar las otras dos opciones, basándome en experiencia real.


Tres formas de inyección: lo esencial primero

Antes de complicarnos, fijemos la base. En Swift hay tres formas principales de proporcionar dependencias.

  1. Inyección por constructor (init)init recibe dependencias como parámetros
  2. Inyección por propiedadvar asignarlas después a una propiedad
  3. Inyección por método — inyectarlas mediante un método independiente

Este es el código de la opción más recomendada: la inyección por constructor.

final class OrderService {
    private let repo: MemberRepository // let garantiza la inmutabilidad

    init(repo: MemberRepository) { // constructor(init) inyección
        self.repo = repo
    }
}

Funciona solo con la sintaxis nativa de Swift, sin bibliotecas adicionales, así que el código queda limpio.

En cambio, la inyección por propiedad es así de breve.

final class OrderService {
    var repo: MemberRepository! // parece cómoda porque ocupa una sola línea…
}

A primera vista, la inyección por propiedad parece claramente más sencilla. Pero esa comodidad puede causar problemas después.


¿Por qué se desaconseja la inyección por propiedad?

Empezaré por algo que viví personalmente.

La inyección por propiedad resulta muy incómoda al hacer pruebas. Si olvidas inyectar después de crear el objeto, aparece un fallo por desempaquetado forzoso y el tipo, por sí solo, no indica qué debes proporcionar para completarlo.

Con inyección por constructor, puedes introducir directamente un mock como OrderService(repo: mockRepo) usando código Swift puro.

El segundo problema es que no puedes usar la palabra clave let.

La inyección por constructor permite declarar las propiedades como let, de modo que quedan inmutables tras la inyección.

La inyección por propiedad, en cambio, usa var, por lo que el valor puede cambiarse en cualquier momento y aumenta el riesgo de errores.

El tercer problema son las referencias circulares.

Si A referencia a B y B a A, la inyección por propiedad puede no detectarlo hasta que la app se ejecuta. El fallo aparece al entrar en esa pantalla.

La inyección por constructor revela el problema al crear el objeto (y, si el diseño está mal planteado, ni siquiera compila), por lo que puedes detectarlo mucho antes.

Las referencias circulares fallan en momentos distintos
Las referencias circulares fallan en momentos distintos
Probar era agotador cuando solo usaba inyección por campos
Probar era agotador cuando solo usaba inyección por campos

Tabla comparativa de un vistazo

Explicarlo con palabras puede confundir, así que lo resumí en una tabla. (Recomendación de la comunidad Swift en 2026)

Categoría Inyección por constructor (init) Inyección por propiedad Inyección por método
Inmutabilidad (let) Posible ⭕ No posible ❌ No posible ❌
Facilidad para probar Alta Baja Media
Detección de referencias circulares Inmediata al crear Se detecta tarde Se detecta tarde
Dependencia obligatoria/opcional Adecuada para obligatorias Distinción ambigua Adecuada para opcionales
Concisión del código Media Muy concisa Media

La tendencia se ve claramente en la tabla, ¿verdad?

La inyección por constructor destaca en la mayoría de los aspectos. Por eso la documentación de bibliotecas DI como Swinject y Factory la recomienda como opción predeterminada.


Entonces, ¿cuándo se usan las otras dos formas?

No significa que debas usar siempre la inyección por constructor. Cada opción tiene su lugar.

La inyección por método funciona bien para dependencias opcionales.

Cuando el objetivo de la inyección no es obligatorio —se usa si está disponible, pero se puede prescindir de él— puedes incorporarlo con flexibilidad mediante un método como configure(with:).

La inyección por propiedad aún tiene sentido cuando no controlamos directamente la inicialización, por ejemplo, en un view controller creado mediante storyboard.

En el código normal de la aplicación, conviene evitarla siempre que sea posible.

En resumen:

  • Dependencia obligatoria → inyección por constructor
  • Dependencia opcional → inyección por método
  • Inyección por propiedad en código general → evitar

Preguntas frecuentes

P. ¿Las bibliotecas DI como Factory facilitan la inyección por constructor?

Sí. Si registras en Swinject o Factory cómo crear las dependencias, el contenedor crea por ti los objetos que se pasan al constructor. El código se acorta y conserva ventajas como la let inmutabilidad.

P. ¿Qué ocurre si el constructor acaba teniendo demasiados parámetros?

No es un problema de la forma de inyección, sino una señal de que la clase hace demasiadas cosas. Primero, considera dividir responsabilidades entre varias clases.

P. ¿Hace falta una biblioteca DI incluso en un proyecto pequeño?

No. En un proyecto con pocas pantallas, basta con inyección por constructor usando Swift puro, pasando las dependencias directamente init.

Cuando dudes, este orden facilita la elección
Cuando dudes, este orden facilita la elección

Al principio es fácil sentirse atraído por la comodidad de la inyección por propiedad, pero al escribir pruebas y colaborar entiendes por experiencia por qué se destacan tanto las ventajas de la inyección por constructor.

Si tienes dudas, empieza con inyección por constructor. Agradecerás la decisión a medida que crezca el código.