Container de Injeção de Dependência para Swift (iOS/macOS): Swinject
No desenvolvimento moderno de iOS e macOS com Swift, os padrões arquiteturais desempenham um papel fundamental na criação de código sustentável e testável. Uma das ferramentas mais poderosas para implementar o Princípio da Inversão de Dependência (Dependency Inversion Principle) é o Swinject — um container DI leve, porém funcional, escrito em Swift. O Swinject permite gerenciar centralizadamente a criação de objetos e suas dependências, liberando o desenvolvedor da construção manual do grafo de objetos.
O que é Injeção de Dependência e para que serve um container?
Injeção de Dependência (DI) é uma técnica na qual um objeto recebe suas dependências externamente, em vez de criá-las por conta própria. Isso reduz o acoplamento do código e simplifica os testes unitários. No entanto, em projetos grandes, a injeção manual de dependências resulta em código extenso. É aqui que o container DI entra em ação, pois:
- Automatiza a criação e a ligação de objetos
- Gerencia o tempo de vida dos objetos (singletons, novas instâncias)
- Facilita a substituição de implementações (por exemplo, para testes)
- Aumenta a legibilidade e a sustentabilidade do código
Instalação do Swinject
O Swinject pode ser instalado via Swift Package Manager, CocoaPods ou Carthage. Para SPM, adicione em Package.swift:
dependencies: [ .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0")]Ou via CocoaPods:
pod 'Swinject', '~> 2.8'Conceitos principais do Swinject
A biblioteca baseia-se em vários componentes-chave:
- Container — o registrador e resolvedor principal de dependências
- Service — o tipo que é registrado (geralmente um protocolo ou classe)
- Component — a implementação concreta do serviço
- Scope — define o tempo de vida do objeto (transient, graph, container, weak)
Exemplo prático: registro e resolução de dependências
Vamos considerar um cenário típico — um aplicativo com um serviço de autenticação e um controlador que o utiliza.
// Protocolo do serviçoprotocol AuthServiceProtocol { func login(username: String, password: String) -> Bool}
// Implementaçãoclass AuthService: AuthServiceProtocol { func login(username: String, password: String) -> Bool { // Lógica de autenticação return username == "admin" && password == "1234" }}
// Controlador dependente de AuthServiceProtocolclass LoginViewController { private let authService: AuthServiceProtocol // Injeção via inicializador init(authService: AuthServiceProtocol) { self.authService = authService } func authenticate(user: String, pass: String) { if authService.login(username: user, password: pass) { print("Login bem-sucedido") } else { print("Dados inválidos") } }}
// Configuração do containerlet container = Container()container.register(AuthServiceProtocol.self) { _ in AuthService() }container.register(LoginViewController.self) { r in LoginViewController(authService: r.resolve(AuthServiceProtocol.self)!)}
// Usolet controller = container.resolve(LoginViewController.self)!controller.authenticate(user: "admin", pass: "1234") // Login bem-sucedidoGerenciamento do tempo de vida (Scopes)
O Swinject suporta quatro scopes integrados:
- .transient — uma nova instância é criada a cada vez (padrão)
- .graph — uma instância por grafo de resolução (usado por padrão na maioria dos casos)
- .container — singleton dentro do container
- .weak — referência fraca, obj
Também na biblioteca
Envio de email em PHP: PHPMailer, SwiftMailer e mail() — guia completo
Cliente OAuth para Swift (iOS/macOS): guia completo