一句话结论(先给判断)
SwiftUI 非常适合复杂业务架构,但前提是:你必须把 SwiftUI 限制在“渲染层”,让业务、状态、副作用完全独立于它。
SwiftUI 不应该成为你的架构核心,
它应该是一个 可替换的 UI Adapter。
一、什么时候 SwiftUI「不适合」复杂业务?
先把坑说清楚:
SwiftUI 不适合复杂业务,通常不是 SwiftUI 的问题,而是使用方式的问题:
- 把业务逻辑写进 View / ViewModel
- 用
@EnvironmentObject当全局状态仓库 - 状态粒度混乱,View 与业务强耦合
- 副作用分散在
.task / onAppear
👉 结果是:
UI ≈ 业务,换 UI 就等于重写系统
二、复杂业务下的正确分层(核心)
你要的不是“SwiftUI 架构”,而是:
业务架构 + SwiftUI 适配层
推荐的五层结构(实践级)
┌──────────────────────────┐
│ SwiftUI View │ ← 纯渲染
├──────────────────────────┤
│ UI Adapter Layer │ ← ViewModel / Presenter
├──────────────────────────┤
│ State / Reducer │ ← 业务状态机(纯)
├──────────────────────────┤
│ UseCase / Domain │ ← 业务规则
├──────────────────────────┤
│ Infrastructure / IO │ ← API / DB / SDK
└──────────────────────────┘
SwiftUI 只占最上面一层。
三、一个“可替换 UI”的核心原则
UI 不拥有 State,只观察 State
正确关系:
State → UI
Action ← UI
而不是:
UI → State → UI
四、可测试的关键:纯业务核心
1️⃣ State + Reducer 是纯函数
struct OrderState {
var items: [Item]
var total: Double
}
enum OrderAction {
case add(Item)
case remove(Item)
}
func orderReducer(
state: inout OrderState,
action: OrderAction
) {
switch action {
case .add(let item):
state.items.append(item)
state.total += item.price
case .remove(let item):
...
}
}
- 不依赖 SwiftUI
- 不依赖线程
- 不依赖时间
👉 100% 可单元测试
2️⃣ 副作用通过协议注入
protocol OrderService {
func submit(_ order: OrderState) async throws
}
- SwiftUI / UIKit 都只是调用方
- 测试中可 mock
五、SwiftUI 层的正确角色
SwiftUI View 只做三件事
- 声明 UI
- 绑定 State 的投影
- 发 Action
struct OrderView: View {
let state: OrderState
let send: (OrderAction) -> Void
var body: some View {
List(state.items) { item in
Text(item.name)
}
Button("Submit") {
send(.submit)
}
}
}
- View 无逻辑
- 无副作用
- 无业务判断
六、UI Adapter 层(被严重低估的一层)
你可以叫它:
- ViewModel
- Presenter
- Store
- Feature Adapter
职责:
- 把业务 State 映射成 UI 需要的形态
- 管理 UI 生命周期相关逻辑(但不进业务)
final class OrderViewAdapter: ObservableObject {
@Published var viewState: OrderViewState
func send(_ action: OrderAction) {
...
}
}
👉 这一层是 SwiftUI 唯一“认识”的业务层
七、为什么这种架构“可替换 UI”?
因为:
- UIKit / SwiftUI / Web
都只需要实现:
render(State)
send(Action)
你的业务核心完全不变。
八、可扩展性的来源
1️⃣ Feature-level 隔离
-
每个 Feature:
- State
- Action
- Reducer
- Adapter
-
无跨 Feature 状态修改
2️⃣ 组合而不是继承
- State 组合
- Reducer 组合
- View 组合
这正是 TCA / Redux 的优势。
九、什么时候用 TCA?什么时候不用?
TCA 非常适合:
- 多 Feature 协作
- 强一致性需求
- 高并发 / 高可测试性
不必 TCA 的情况:
- 页面级简单逻辑
- 快速原型
你可以:
核心 Feature 用 TCA,边缘 Feature 用轻量 MVVM
十、真实项目里的“最低风险方案”
“TCA-like,不一定用 TCA”
- 单一 State
- Action 驱动
- Reducer 纯函数
- SwiftUI 只 render
你已经拿到 80% 的收益。
最终一句话(架构级)
SwiftUI 非常适合复杂业务,但前提是:
它只负责‘画’,而你的系统已经决定了‘发生什么’。