模块化与依赖注入
问题
大型 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 容器(如 Swinject、Factory):
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。