Swinject: o que é, princípios de Dependency Injection e como funciona

Autor: IT Sectr Publicado: 2026-05-04 Tempo de leitura: 8 min

Swinject é um contêiner DI para Swift que implementa o padrão Dependency Injection em aplicações iOS. O framework automatiza a criação e injeção de dependências, eliminando o gerenciamento manual de objetos e fábricas. De acordo com Swinject no GitHub, a biblioteca suporta Constructor Injection, Property Injection e Method Injection com um flexível sistema de scopes para gerenciamento de tempo de vida.

Principais pontos

  • Swinject — um contêiner DI para Swift que automatiza a injeção de dependência em projetos iOS.
  • Dependency Injection — um padrão onde um objeto recebe suas dependências externamente em vez de criá-las internamente.
  • Container — o componente central do Swinject que armazena um registro de serviços registrados e suas fábricas.
  • Service — uma abstração em forma de protocolo para a qual o contêiner armazena uma implementação concreta.
  • ObjectScope — um mecanismo que determina o tempo de vida da instância: graph, container ou transient.

O que é Swinject e Dependency Injection

Swinject é um contêiner DI de código aberto para a linguagem Swift, projetado para simplificar a injeção de dependência em aplicações para iOS, macOS e watchOS. O framework utiliza a abordagem Service Locator: os serviços são registrados em um contêiner central, e o contêiner resolve automaticamente o grafo de dependências quando uma instância é solicitada.

Dependency Injection (DI) é um padrão de design onde um objeto recebe suas dependências externamente em vez de criá-las internamente. Isso reduz o acoplamento entre componentes, simplifica os testes unitários e permite substituir implementações sem modificar o código do consumidor.

De acordo com Martin Fowler (2004), DI é um caso específico de Inversion of Control e é implementado através de injeção por construtor, propriedade ou método. Swinject automatiza esse processo, eliminando a necessidade de escrever fábricas e localizadores de serviços manualmente.

Use Swinject em projetos com três ou mais serviços que tenham dependências cruzadas, onde a construção manual de objetos leva ao inchaço do código de inicialização e à redução da testabilidade.

Swinject integra-se estreitamente com o ecossistema Apple e suporta todas as versões do Swift a partir da 3.0. O framework é compatível com Objective-C através de pontes, permitindo sua introdução em projetos existentes em linguagem mista sem uma migração completa de código. Isso é especialmente relevante para aplicações grandes com mais de cinco anos de desenvolvimento.

Como funciona o contêiner Swinject

O contêiner Swinject é implementado pela classe Container, que armazena um registro de serviços registrados. Quando o método resolve é chamado, o contêiner cria um objeto, resolvendo todas as suas dependências recursivamente através do grafo de registros.

Container e Service

Container é o objeto central onde as correspondências entre abstrações e suas implementações são registradas. Service é um protocolo que define um contrato, enquanto Component é uma classe que implementa esse protocolo. O registro é feito usando o método register, que recebe o tipo de serviço e uma fábrica.

swift
let container = Container()
container.register(Networking.self) { _ in
    NetworkService()
}
let service = container.resolve(Networking.self)

O método resolve retorna uma instância da implementação concreta registrada para o protocolo especificado. Se uma dependência não estiver registrada, o contêiner lança um erro fatal para detecção rápida do problema durante o desenvolvimento.

Registro e serviços nomeados

Cada registro cria uma entrada com uma função de fábrica e um escopo selecionado. Um mesmo serviço pode ter vários registros com nomes diferentes, permitindo selecionar uma implementação específica pelo nome — útil para diferentes ambientes (desenvolvimento, staging, produção).

O processo de resolução de dependências funciona recursivamente: quando o contêiner cria uma instância de Component, ele analisa seu inicializador e para cada parâmetro chama resolve com o tipo correspondente. Se uma dependência também tem suas próprias dependências, o processo continua até que todo o grafo esteja completamente construído. A profundidade de aninhamento é limitada apenas pela memória disponível, mas na prática raramente excede cinco níveis.

Métodos de injeção de dependência no Swinject

Swinject suporta três métodos principais de injeção de dependência, cada um aplicável dependendo do contexto arquitetural.

Constructor Injection

Constructor Injection injeta dependências através de parâmetros do inicializador. Este é o método preferido, garantindo que um objeto esteja sempre em um estado válido desde o momento da criação. Swinject resolve automaticamente todas as dependências passadas ao construtor.

swift
class LoginViewModel {
    private let authService: AuthProtocol

    init(authService: AuthProtocol) {
        self.authService = authService
    }
}

container.register(AuthProtocol.self) { _ in
    AuthService()
}
container.register(LoginViewModel.self) { r in
    LoginViewModel(authService: r.resolve(AuthProtocol.self)!)
}

Property Injection

Property Injection injeta dependências definindo propriedades do objeto após a inicialização. É usado quando uma dependência é opcional ou não pode ser passada através do construtor, por exemplo, ao trabalhar com Storyboard, onde o view controller é criado automaticamente. Swinject suporta a anotação @Inject para injeção automática de propriedades em tempo de execução sem uma chamada explícita a resolve.

Ao usar Property Injection, é importante garantir que a dependência seja definida antes do primeiro acesso ao objeto. Caso contrário, a propriedade permanecerá nil, levando a uma queda inesperada. Swinject resolve esse problema através do mecanismo Implicitly Unwrapped Optional e validação rigorosa no estágio de resolução do grafo de dependências.

Method Injection

Method Injection injeta dependências através de parâmetros de método. É usado para serviços que são necessários apenas para realizar uma única operação e não devem ser armazenados como estado permanente do objeto. Este é o método menos comum, mas útil para callbacks.

Scopes no Swinject e sua finalidade

ObjectScope é um mecanismo que determina o tempo de vida de uma instância criada dentro do contêiner Swinject. O framework fornece três escopos integrados com a capacidade de criar personalizados através do ObjectScopeProtocol.

ObjectScope.graph

O escopo graph é o valor padrão. Cada chamada a resolve cria uma nova instância que vive apenas durante a resolução do grafo de dependências. É uma escolha segura para serviços sem estado, pois elimina vazamentos de memória por cache.

ObjectScope.container

O escopo container é um singleton dentro do contêiner. A instância é criada uma vez no primeiro resolve e retornada em todas as solicitações subsequentes. Adequado para serviços com estado compartilhado: cache de dados, logger, configurações do aplicativo.

ObjectScope.transient

O escopo transient cria uma nova instância em cada chamada a resolve sem cache. Usado para objetos leves que não precisam ser reutilizados — por exemplo, módulos que lidam com uma solicitação HTTP específica.

EscopoTempo de vidaUso recomendado
graphDurante a resolução do grafoServiços sem estado por padrão
containerToda a vida do contêinerSingletons: cache, logger, cliente de rede
transientSem cacheObjetos leves para uso único

Swinject em projetos iOS

A integração do Swinject em um projeto iOS real começa com a inicialização do contêiner na inicialização do aplicativo — no AppDelegate ou na cena. Recomenda-se estruturar os registros usando Assembly: uma classe ou estrutura separada que agrupa serviços relacionados.

De acordo com uma pesquisa da Swift Developer Community (2025), 43% dos desenvolvedores iOS usam contêineres DI em projetos comerciais para gerenciar dependências da camada de rede, repositórios e coordenadores de navegação. Swinject continua sendo a solução mais popular devido à sua sintaxe mínima e compatibilidade com Objective-C.

Storyboard Injection é um recurso único do Swinject: o contêiner injeta automaticamente dependências em view controllers criados a partir do Storyboard sem código adicional no AppDelegate. Isso usa um resolvedor especial passado para UIStoryboard através do método init(container:), que intercepta a criação do view controller e injeta as dependências registradas.

Em projetos grandes, o Swinject pode ser combinado com coordenadores de navegação: o coordenador recebe o contêiner e cria telas resolvendo suas dependências através de resolve, mantendo um único ponto de configuração para toda a cena.

A arquitetura Assembly é o padrão recomendado para organizar os registros. Cada Assembly agrupa serviços relacionados (por exemplo, NetworkingAssembly, DatabaseAssembly) e pode depender de outros Assemblies. Ao inicializar o contêiner, todos os Assemblies são carregados e registram seus serviços, fornecendo clara separação de responsabilidades e simplificando a navegação pela configuração DI em projetos grandes com dezenas de serviços.

Para depuração do grafo DI, o Swinject fornece a extensão SwinjectPropertyLoader, que carrega a configuração de um arquivo plist, e SwinjectStoryboard — integração com storyboards através de uma versão especial do UIStoryboard. Essas ferramentas são especialmente úteis ao migrar um projeto existente da construção manual de objetos para DI: o desenvolvedor pode registrar serviços gradualmente, verificando o grafo de dependências através de testes e registro de erros de resolução sem interromper o desenvolvimento dos recursos principais.

O Swinject também oferece integração com RxSwift e Combine através da extensão SwinjectAutoregistration para resolução automática de dependências com base nos tipos de parâmetros do inicializador sem registro explícito de fábrica. Isso reduz a quantidade de código de registro para serviços simples: basta chamar container.register(ServiceProtocol.self) sem especificar uma fábrica, e o Swinject construirá automaticamente a fábrica com base na reflexão Signal fornecida pelo runtime do Swift. Esta abordagem é recomendada para serviços cujos construtores aceitam apenas tipos básicos e não exigem lógica de criação complexa.

Perguntas frequentes

Como o Swinject difere de outros frameworks DI para Swift?

Swinject é escrito em Swift puro sem geração de código ou reflexão. Ao contrário do Needle, não requer geração de fontes, e comparado ao Dip, fornece suporte integrado para Storyboard Injection, simplificando a integração em projetos UIKit existentes.

Como instalar o Swinject via Swift Package Manager?

Adicione o pacote via URL github.com/Swinject/Swinject através do Xcode no menu File — Add Packages. A instalação via CocoaPods e Carthage também está disponível. Após a instalação, importe o módulo Swinject e crie uma instância de Container.

Posso usar Swinject em projetos SwiftUI?

Sim, Swinject é totalmente compatível com SwiftUI. As dependências são injetadas através dos inicializadores da View ou através do Environment, onde o contêiner é passado como EnvironmentObject. Swinject não depende do UIKit e funciona igualmente bem com ambos os frameworks.

Como usar Swinject para testes unitários?

Crie um contêiner separado para testes, substituindo serviços reais por mocks. Swinject permite sobrescrever registros sem alterar o código dos consumidores. Cada teste recebe um contêiner isolado com um conjunto mínimo de dependências.

Qual escopo escolher para um serviço de análise?

Para análise, use o escopo container para que todas as telas enviem eventos através de uma única instância. Isso garante uma fila de envio unificada e a operação correta de agregação em lote sem duplicação de dados entre diferentes consumidores.

Resumo

  • Swinject — um contêiner DI para Swift que automatiza a injeção de dependência através de Container e ObjectScope.
  • Dependency Injection reduz o acoplamento do código, simplifica os testes e permite substituir implementações sem alterar os consumidores.
  • Container — um registro de serviços que suporta register para registro e resolve para obtenção de instância.
  • Constructor Injection é o método de injeção preferido, garantindo o estado válido do objeto.
  • ObjectScope gerencia o tempo de vida: graph (padrão), container (singleton) e transient (sem cache).
  • Storyboard Injection injeta automaticamente dependências em cenas UIKit sem configuração manual.
  • Para testes unitários, use um contêiner separado com implementações mock dos serviços.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também