不使用 DI 框架组装各层
使用组合根模式在应用入口处组合对象。
不使用 DI 框架组装各层 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。
组合根
组合根是实例化所有对象并将它们连接在一起的唯一位置。在 SwiftUI 应用中,它通常是 @main。
@main
struct MyApp: App {
// All wiring happens here
private let container = AppContainer()
var body: some Scene {
WindowGroup { container.makeRootView() }
}
}AppContainer 模式
AppContainer 结构体或类负责构建对象图,将装配的复杂性隐藏在应用结构体之外。
final class AppContainer {
let db = SQLiteDatabase()
lazy var userRepo: UserRepository = RemoteUserRepository(db: db)
lazy var fetchUser = FetchUserUseCase(repo: userRepo)
lazy var profileVM = ProfileViewModel(useCase: fetchUser)
func makeRootView() -> some View { ProfileView(viewModel: profileVM) }
}使用延迟属性控制顺序
使用 lazy 属性,确保依赖项按正确顺序构建,而无需手动安排顺序。
final class Container {
lazy var network: NetworkClient = URLSessionClient()
lazy var api: APIService = APIService(client: network) // created after network
lazy var repo: ItemRepository = RemoteItemRepository(api: api)
}工厂方法
向容器添加工厂方法,以创建具有各屏幕专属依赖的视图层对象。
extension AppContainer {
func makeOrderFlow() -> OrderFlowView {
let repo = RemoteOrderRepository(api: api)
let useCase = PlaceOrderUseCase(repo: repo)
let vm = OrderViewModel(useCase: useCase)
return OrderFlowView(viewModel: vm)
}
}使用环境值进行注入
在 SwiftUI 中,使用自定义 EnvironmentKey 将依赖注入视图树的深层,而无需逐层传递属性。
private struct FetchUserKey: EnvironmentKey {
static let defaultValue: FetchingUser = FetchUserUseCase(repo: NullUserRepo())
}
extension EnvironmentValues {
var fetchUser: FetchingUser {
get { self[FetchUserKey.self] } set { self[FetchUserKey.self] = newValue }
}
}使用环境键
通过 .environment(\.fetchUser, container.fetchUser) 注入依赖,并在视图中使用 @Environment(\.fetchUser) 读取。
ContentView()
.environment(\.fetchUser, container.fetchUser)
// In a deep view:
@Environment(\.fetchUser) private var fetchUser作用域容器
为功能作用域创建子容器,继承共享依赖,同时拥有功能专属依赖。
final class CheckoutContainer {
let cart: CartRepository
let payment: PaymentService
lazy var placeOrder = PlaceOrderUseCase(cart: cart, payment: payment)
init(parent: AppContainer) {
cart = parent.cartRepo
payment = parent.paymentService
}
}测试组合根
测试容器的工厂方法,验证返回对象具有正确的类型和配置。
func testContainerBuildsProfileView() {
let container = AppContainer(db: InMemoryDatabase())
let view = container.makeRootView()
XCTAssertTrue(type(of: view) == ProfileView.self)
}避免循环依赖
如果 A 依赖 B,而 B 又依赖 A,请引入中介者或重新划分职责,以打破循环。
// Circular:
// UserService → NotificationService → UserService
// Fix: UserService → NotificationInput (protocol) ← NotificationService何时使用依赖注入框架
手动装配足以应对中等规模的应用。只有当容器变得难以维护时,才考虑使用框架(Needle、Swinject)。
// Manual: fine for <20 top-level dependencies
// Framework: helps with large teams, 50+ services, code-generation for factories回顾示例
小型应用中的完整装配示例:容器构建所有依赖,工厂生成根视图。
final class AppContainer {
private let db = CoreDataStack.shared
lazy var userRepo: UserRepository = LocalUserRepository(db: db)
lazy var fetchUser = FetchUserUseCase(repo: userRepo)
func makeContentView() -> ContentView {
ContentView(viewModel: ProfileViewModel(useCase: fetchUser))
}
}快速检查
Swift 应用中的组合根是什么?
课程回顾
在组合根(通常是 @main)中装配应用。使用包含 lazy 属性的 AppContainer,确保正确的构建顺序。添加工厂方法,为每个屏幕创建独立对象图。通过自定义 EnvironmentKey 将深层依赖注入视图。使用中介者协议打破循环依赖。
用 AI 导师学习 Swift — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 122
- 课程
- 409
常见问题解答
「不使用 DI 框架组装各层」课时是免费的吗?
是的 — 「不使用 DI 框架组装各层」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。
「不使用 DI 框架组装各层」这节课中我会学到什么?
使用组合根模式在应用入口处组合对象。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Swift Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「不使用 DI 框架组装各层」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Swift Academy 课中编写并运行代码吗?
能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 分层:领域、数据与表示层
- 用例与仓储模式
- 使用协议抽象实现依赖倒置
- 不使用 DI 框架组装各层