跳到主要内容

模块化与依赖注入

问题

大型 iOS 项目如何实现模块化?依赖注入怎么用?

答案

模块化分层

模块化原则
  • Feature 模块之间不互相依赖
  • Feature 依赖 Core,Core 依赖 Foundation
  • 模块间通过 Protocol 通信

依赖注入

// 1. 定义协议
protocol UserServiceProtocol {
func fetchUsers() async throws -> [User]
}

// 2. 实现
class UserService: UserServiceProtocol {
func fetchUsers() async throws -> [User] { ... }
}

// 3. 注入(构造器注入)
class UserListViewModel: ObservableObject {
private let service: UserServiceProtocol

init(service: UserServiceProtocol = UserService()) {
self.service = service
}
}

// 4. 测试时替换
class MockUserService: UserServiceProtocol {
func fetchUsers() async throws -> [User] {
[User(name: "Test", age: 1)]
}
}

let vm = UserListViewModel(service: MockUserService())

DI 容器

大型项目可使用 DI 容器(如 SwinjectFactory):

import Factory

extension Container {
var userService: Factory<UserServiceProtocol> {
Factory(self) { UserService() }
}
}

class UserListViewModel: ObservableObject {
@Injected(\.userService) private var service
}

常见面试问题

Q1: 构造器注入、属性注入、方法注入的区别?

答案

  • 构造器注入(推荐):init(service:) — 依赖明确、不可变、保证完整初始化
  • 属性注入vm.service = xxx — 灵活但容易遗漏
  • 方法注入func load(service:) — 仅在特定方法需要时使用

Q2: Swift Package Manager 和 CocoaPods 做模块化的区别?

答案:SPM 是 Apple 官方方案,原生集成 Xcode,支持本地包开发。CocoaPods 是第三方,模板代码多但生态成熟。新项目推荐 SPM。

相关链接