MVI架构详解
什么是MVI MVI(Model-View-Intent)是一种单向数据流架构模式。“Model-View-Intent"这一命名最早出现在Andre Medeiros(Staltz)创建的JavaScript框架Cycle.js中。2016年,Hannes Dorfmann在其博客系列中将MVI系统化引入Android开发,他在文中明确提到同时受到了Cycle.js和Redux(以及更早的Elm架构)的启发——MVI的命名和响应式理念来自Cycle.js,而Reducer纯函数和单一状态源的机制则与Redux一脉相承。随着Swift社区对函数式编程和响应式编程的接受度提高,MVI也逐渐被引入iOS开发。 MVI的核心思想: 单向数据流:数据沿固定方向流动(View -> Intent -> Reducer -> State -> View),没有捷径或后门 不可变状态:整个界面由单一不可变的State描述,每次更新都产生全新的State对象 可预测性:给定相同的当前State和Intent,Reducer总是产生相同的新State MVI的核心概念 Model(状态) 在MVI中,Model不是传统意义上的领域数据模型,而是界面状态模型(State)。它用一个不可变的值类型来描述UI在某一时刻的完整快照,包括数据内容、加载状态、错误信息等。 struct UserListState: Equatable { var users: [User] var isLoading: Bool var error: String? var searchQuery: String static let initial = UserListState( users: [], isLoading: false, error: nil, searchQuery: "" ) } 这里使用var属性配合struct值类型,利用Swift的值语义在Reducer中通过拷贝实现不可变效果,这是Swift中最常用的做法(详见后文"状态的不可变性"一节)。 Intent(意图) Intent代表所有触发状态变化的事件。它不仅包括用户的UI操作,还包括副作用的结果回调(如网络请求完成、数据库查询结果)、系统事件(如生命周期回调、推送通知)等。所有这些事件统一通过Intent进入Reducer驱动状态变化。 enum UserListAction { // 用户意图 case loadUsers case refreshUsers case deleteUser(id: Int) case searchQueryChanged(String) // 副作用结果(也是Intent的一种) case usersLoaded([User]) case loadFailed(String) } 将用户操作和副作用结果统一为同一类型,是MVI的关键设计。这样Reducer就成为状态变化的唯一入口,所有状态转换都在一处完成。 ...