📦 Dependency Injection in Swift — Complete Swift Guide
💡 What is Dependency Injection?
📦 Dependency Injection in Swift — Complete Swift Guide
💡 What is Dependency Injection?
Definition: Dependency Injection (DI) is a design pattern where dependencies (objects needed by a class) are provided from the outside instead of being created internally.
❌ Without Dependency Injection
class Engine {
func start() {
print("Engine started")
}
}
class Car {
let engine = Engine() // tightly coupled
func drive() {
engine.start()
print("Car is moving")
}
}
let car = Car()
car.drive()
Problem: Car creates its own Engine, making it hard to test or swap the engine.
✅ With Constructor Injection (Recommended)
class Engine {
func start() {
print("Engine started")
}
}
class Car {
let engine: Engine
init(engine: Engine) {
self.engine = engine
}
func drive() {
engine.start()
print("Car is moving")
}
}
let engine = Engine()
let car = Car(engine: engine)
car.drive()
✅ Benefits: Car doesn’t care where Engine comes from. Easily testable and replaceable.
🎯 Protocol-Oriented Injection (For Mocks)
Step 1: Create Protocol
protocol EngineProtocol {
func start()
}
Step 2: Real Engine
class RealEngine: EngineProtocol {
func start() {
print("🚗 Real engine starts")
}
}
Step 3: Mock Engine for Testing
class MockEngine: EngineProtocol {
func start() {
print("🧪 Mock engine used for testing")
}
}
Step 4: Inject via Protocol
class TestableCar {
let engine: EngineProtocol
init(engine: EngineProtocol) {
self.engine = engine
}
func drive() {
engine.start()
print("TestableCar is moving")
}
}
// Production
let realCar = TestableCar(engine: RealEngine())
realCar.drive()
// Testing
let testCar = TestableCar(engine: MockEngine())
testCar.drive()
🧰 Property Injection
Inject dependencies via public properties
class Engine {
func start() {
print("Engine starts...")
}
}
class Car {
var engine: Engine?
func drive() {
engine?.start()
print("Car is moving")
}
}
let car = Car()
car.engine = Engine() // inject from outside
car.drive()
⚠️ Not recommended for critical dependencies — harder to track and test.
🧼 Cleanest Way: Property Wrapper Injection (Advanced)
Let’s create a simple custom property injector:
class DependencyContainer {
static let shared = DependencyContainer()
var engine: EngineProtocol = RealEngine()
}
@propertyWrapper
struct Injected<T> {
var wrappedValue: T {
DependencyContainer.shared.engine as! T
}
}
Now inject with a cleaner syntax:
class SmoothCar {
@Injected var engine: EngineProtocol
func drive() {
engine.start()
print("SmoothCar is running")
}
}
let car = SmoothCar()
car.drive()
🔍 When to Use What?
Constructor Injection :- Default & recommended for Swift.
Protocol Injection :- For unit testing & mocking.
Property Injection :- Optional or swappable dependencies.
Property Wrapper DI :- Global shared dependencies (advanced use).
🧪 Unit Testing with Mocks
func testCarWithMockEngine() {
let mockEngine = MockEngine()
let testCar = TestableCar(engine: mockEngine)
testCar.drive()
// Output: 🧪 Mock engine used for testing
}
✅ Final Thoughts
Dependency Injection makes your Swift code:
- Modular
- Easy to test
- Scalable for large projects
By starting with protocols and constructor injection, you’ll write clean, professional Swift code that’s easy to maintain.
메타데이터
- post_id
- 540b5ce6e20a
- slug
- dependency-injection-in-swift-complete-swift-guide-540b5ce6e20a
- url
- https://medium.com/@nehagupta50525/dependency-injection-in-swift-complete-swift-guide-540b5ce6e20a
- canonical_url
- https://medium.com/@nehagupta50525/dependency-injection-in-swift-complete-swift-guide-540b5ce6e20a
- author_url
- https://medium.com/@nehagupta50525
- status
- ok
- fetched_at
- 2026-07-13 06:23:13