Swift Academy · 课时

不使用 DI 框架组装各层

使用组合根模式在应用入口处组合对象。

第 4 / 4 课13 个步骤

不使用 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 分层:领域、数据与表示层
  2. 用例与仓储模式
  3. 使用协议抽象实现依赖倒置
  4. 不使用 DI 框架组装各层
← 返回 Swift Academy