一、VIPER 里 Interactor 和 Presenter 的职责
| 层 | 核心职责 |
|---|---|
| Interactor | 纯业务逻辑 + 数据处理(网络请求、数据库、计算) 不关心 UI 或视图状态 |
| Presenter | UI 表示逻辑 + 视图事件处理 把业务数据转成 ViewModel / 展示模型 |
| 关系原则 | 单向依赖:Presenter 可以调用 Interactor,但 Interactor 不直接依赖 Presenter |
⚠️ VIPER 核心理念:依赖倒置 + 单向流
业务逻辑层(Interactor)不应该知道 Presenter 或 View 的存在。
二、为什么容易反向依赖
在实践中常见的反向依赖情景:
class UserInteractor {
var presenter: UserPresenter? // ❌ 直接持有 Presenter
func fetchUser() {
let user = api.getUser()
presenter?.didFetchUser(user) // ❌ Interactor 调用 Presenter
}
}
问题:
- Interactor 知道了 Presenter,违反 VIPER 的依赖倒置原则
- Presenter 和 Interactor 相互持有 → 循环依赖
- 当需要单元测试 Interactor 时,必须提供 Presenter mock → 耦合高
三、正确划分边界:协议 + 单向回调
1️⃣ Interactor 不直接依赖 Presenter,而依赖协议
protocol UserInteractorOutput: AnyObject {
func didFetchUser(_ user: User)
}
class UserInteractor {
weak var output: UserInteractorOutput? // 弱引用,避免循环
func fetchUser() {
let user = api.getUser()
output?.didFetchUser(user)
}
}
- Interactor 只依赖协议
- Presenter 实现协议
- 单向依赖:Presenter → Interactor
2️⃣ Presenter 调用 Interactor
class UserPresenter: UserInteractorOutput {
private let interactor: UserInteractor
init(interactor: UserInteractor) {
self.interactor = interactor
self.interactor.output = self // 单向回调
}
func loadUser() {
interactor.fetchUser() // 调用 Interactor
}
// MARK: - UserInteractorOutput
func didFetchUser(_ user: User) {
let viewModel = UserViewModel(name: user.name.uppercased())
view?.display(user: viewModel)
}
}
- Presenter 调用 Interactor → 业务请求
- Interactor 通过 协议回调 → Presenter 收到结果
- Interactor 不知道 Presenter 存在,只依赖
UserInteractorOutput协议
3️⃣ 优势
-
单向依赖
- Presenter → Interactor
- Interactor → 协议(不依赖 Presenter)
-
测试友好
- Interactor 可以独立测试,只用 mock
UserInteractorOutput
- Interactor 可以独立测试,只用 mock
-
解耦清晰
- Interactor 不管 View 或 Presenter 如何展示数据
- Presenter 只处理 UI 表示逻辑
4️⃣ 总结原则
| 原则 | 做法 |
|---|---|
| 依赖倒置 | Interactor 依赖协议,不依赖 Presenter |
| 单向数据流 | Presenter 调用 Interactor,Interactor 用协议回调结果 |
| 弱引用 / 单向回调 | 避免循环引用 |
| UI逻辑隔离 | Interactor 不处理 ViewModel / UI 展示逻辑 |
核心思想一句话:Interactor 做“干净的业务”,Presenter 做“干净的 UI”,中间靠协议桥接,不直接握手