Bootstrap Guide
How to safely and consistently prepare dependencies at app startup. WeaveDI provides various bootstrap patterns to flexibly configure synchronous/asynchronous initialization, test isolation, conditional initialization, and more.
Overview
- Goal: Clearly initialize necessary dependencies in one place at app startup
- Features:
- Synchronous/asynchronous/mixed bootstrap support
- Atomic replacement of global container (thread-safe)
- Test isolation/reset API provided
When to Use
- Called only once in AppDelegate/SceneDelegate/app entry points
- In SwiftUI App structure, at
@main
entry point or initial View-Model configuration
Synchronous Bootstrap
import WeaveDI
await DIContainer.bootstrap { container in
container.register(Logger.self) { ConsoleLogger() }
container.register(Networking.self) { DefaultNetworking() }
container.register(UserRepository.self) { UserRepositoryImpl() }
}
// Afterwards, DIContainer.shared.resolve(...) can be used anywhere
let logger = DIContainer.shared.resolve(Logger.self)
Asynchronous Bootstrap
When asynchronous initialization is needed (e.g., remote configuration, database connections), use bootstrapAsync
.
let ok = await DIContainer.bootstrapAsync { container in
// Example: Load remote configuration
let config = try await RemoteConfig.load()
container.register(AppConfig.self) { config }
// Example: Initialize async resources
let db = try await Database.open()
container.register(Database.self) { db }
}
guard ok else { /* Handle failure (splash/notification/retry) */ return }
Note:
bootstrapAsync
can be configured tofatalError
on failure in DEBUG builds and returnfalse
in RELEASE builds. Current implementation provides Bool return with internal logging.
Mixed Bootstrap (sync + async)
Useful when you want core dependencies immediately and supplementary dependencies asynchronously.
@MainActor
await DIContainer.bootstrapMixed(
sync: { container in
container.register(Logger.self) { ConsoleLogger() }
container.register(Networking.self) { DefaultNetworking() }
},
async: { container in
// Async extended dependencies
let analytics = await AnalyticsClient.make()
container.register(AnalyticsClient.self) { analytics }
}
)
Bootstrap in Background Task
When you want to minimize app startup delay, you can perform asynchronous bootstrap in the background.
DIContainer.bootstrapInTask { container in
let featureFlags = try await FeatureFlags.fetch()
container.register(FeatureFlags.self) { featureFlags }
}
Conditional Bootstrap
Use when you want to skip if already initialized.
let didInit = await DIContainer.bootstrapIfNeeded { container in
container.register(Logger.self) { ConsoleLogger() }
}
if !didInit {
// Already prepared
}
Asynchronous version is also provided.
let didInit = await DIContainer.bootstrapAsyncIfNeeded { container in
let config = try await RemoteConfig.load()
container.register(AppConfig.self) { config }
}
Reset for Testing
In test environments, you can reset and reconfigure the container.
// In test setup
await DIContainer.resetForTesting()
await DIContainer.bootstrap { container in
// Register test doubles
container.register(Logger.self) { MockLogger() }
container.register(UserRepository.self) { TestUserRepository() }
}
Production Example
@main
struct MyApp: App {
@State private var isInitialized = false
var body: some Scene {
WindowGroup {
if isInitialized {
ContentView()
} else {
SplashView()
.task {
await initializeDependencies()
isInitialized = true
}
}
}
}
private func initializeDependencies() async {
await DIContainer.bootstrapMixed(
sync: { container in
// Core dependencies
container.register(Logger.self) { ProductionLogger() }
container.register(Networking.self) { URLSessionNetworking() }
},
async: { container in
// Async dependencies
let config = try? await RemoteConfig.load()
container.register(AppConfig.self) { config ?? AppConfig.default }
}
)
}
}
Best Practices
- Single bootstrap: Call bootstrap only once at app startup
- Error handling: Always handle bootstrap failures gracefully
- Test isolation: Use
resetForTesting()
in test setup - Performance: Use mixed bootstrap for optimal startup time
- Conditional: Use
bootstrapIfNeeded
for hot reloading scenarios
📖 Documentation: |