UUID and Date initializers, and even clocks.
Overview
By controlling the dependencies our features need to do their job we gain the ability to completely alter the execution context a feature runs in. This means in tests and Xcode previews you can provide a mock version of an API client that immediately returns some stubbed data rather than making a live network request to a server.The dependency management system in the Composable Architecture is driven by the Dependencies library. That repository has extensive documentation and articles, and we highly recommend you familiarize yourself with all of that content to best leverage dependencies.
Registering dependencies
To register a new dependency, you extendDependencyValues with a computed property:
DependencyKey:
Using dependencies
Once registered, you can access dependencies in your reducers using the@Dependency property wrapper:
Overriding dependencies
You can override dependencies for specific reducers using thedependency modifier:
Feature reducer to use mock versions of dependencies, perfect for controlled environments like onboarding experiences.
Dependency contexts
Dependencies automatically adapt to different execution contexts:Live
Used when running your app normally. Performs real network requests, file I/O, etc.
Preview
Used in Xcode previews. Can provide mock data that displays quickly.
Test
Used in tests. Provides controllable, deterministic behavior.
Failing
Default fallback that crashes if accessed, ensuring you explicitly handle dependencies.
Common dependencies
The library provides several common dependencies out of the box:Clock dependencies
UUID
Date
Main queue
Testing with dependencies
In tests, you can override dependencies using thewithDependencies parameter:
Preview dependencies
You can provide mock data for Xcode previews:Best practices
Make dependencies Sendable
Make dependencies Sendable
All dependencies should be
Sendable since they can be used from asynchronous and concurrent contexts. Use @Sendable closures for any function-based endpoints:Use live implementations by default
Use live implementations by default
The
liveValue should be your real, production implementation. Other values like testValue and previewValue are optional.Keep interfaces minimal
Keep interfaces minimal
Only expose the operations your features actually need. A smaller interface is easier to mock and maintain.
Avoid global state
Avoid global state
Don’t access global state or singletons directly in your reducers. Wrap them in dependencies so they can be controlled in tests.