Expert DI decisions for iOS/tvOS: when DI containers add value vs overkill, choosing between injection patterns, protocol design for testability, and SwiftUI-specific injection strategies. Use when designing service layers, setting up testing infrastructure, or deciding how to wire dependencies. Trigger keywords: dependency injection, DI, constructor injection, protocol, mock, testability, container, factory, @EnvironmentObject, service locator
View on GitHubKaakati/rails-enterprise-dev
reactree-ios-dev
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/Kaakati/rails-enterprise-dev/blob/main/plugins/reactree-ios-dev/skills/dependency-injection/SKILL.md -a claude-code --skill dependency-injectionInstallation paths:
.claude/skills/dependency-injection/# Dependency Injection — Expert Decisions
Expert decision frameworks for dependency injection choices. Claude knows DI basics — this skill provides judgment calls for when and how to apply DI patterns.
---
## Decision Trees
### Do You Need DI?
```
Is the dependency tested independently?
├─ NO → Is it a pure function or value type?
│ ├─ YES → No DI needed (just call it)
│ └─ NO → Consider DI for future testability
│
└─ YES → How many classes use this dependency?
├─ 1 class → Simple constructor injection
├─ 2-5 classes → Protocol + constructor injection
└─ Many classes → Consider lightweight container
```
**The trap**: DI everything. If a helper function has no side effects and doesn't need mocking, don't wrap it in a protocol.
### Which Injection Pattern?
```
Who creates the object?
├─ Caller provides dependency
│ └─ Constructor Injection (most common)
│ init(service: ServiceProtocol)
│
├─ Object creates dependency but needs flexibility
│ └─ Default Parameter Injection
│ init(service: ServiceProtocol = Service())
│
├─ Dependency changes during lifetime
│ └─ Property Injection (rare, avoid if possible)
│ var service: ServiceProtocol?
│
└─ Factory creates object with dependencies
└─ Factory Pattern
container.makeUserViewModel()
```
### Protocol vs Concrete Type
```
Will this dependency be mocked in tests?
├─ YES → Protocol
│
└─ NO → Is it from external module?
├─ YES → Protocol (wrap for decoupling)
└─ NO → Is interface likely to change?
├─ YES → Protocol
└─ NO → Concrete type is fine
```
**Rule of thumb**: Network, database, analytics, external APIs → Protocol. Date formatters, math utilities → Concrete.
### DI Container Complexity
```
Team size?
├─ Solo/Small (1-3)
│ └─ Default parameters + simple factory
│
├─ Medium (4-10)
│ └─ Simple manual container
│ final class Container {
│ lazy var userService = UserService()
│ }
│
└─ Large (10+)
└─ Consider Swinject or similar
(only i