Redux 是前端領域經典的狀態管理模式,核心遵循單向數據流和不可變狀態原則,在 iOS 開發中,可通過原生 Swift 實現 Redux 架構思想,也可藉助第三方庫(如ReSwift)快速落地,適用於複雜應用的全局狀態管理(如用户信息、主題設置、多頁面共享數據等場景)。以下從核心概念、實現方式、實戰案例展開解析:
一、Redux 核心概念(iOS 映射)
|
Redux 概念
|
iOS 中的實現形式
|
作用
|
|
Store |
單例類(含狀態對象 + 派發方法)
|
存儲全局唯一狀態,提供 |
|
Action |
枚舉 / 結構體(含 |
描述 “發生了什麼”,是修改狀態的唯一指令(如 |
|
Reducer |
純函數( |
根據 Action 類型計算新狀態,不可直接修改原狀態(需返回新對象) |
|
State |
結構體(不可變設計)
|
存儲應用狀態(如 |
|
Middleware |
閉包 / 類(攔截 |
處理副作用(如網絡請求、日誌記錄),常見於 |
二、iOS 中實現 Redux 的兩種方式
1. 原生 Swift 手動實現 Redux(輕量場景)
步驟 1:定義 State(不可變狀態)
swift
// 應用全局狀態
struct AppState {
var user: User? // 用户信息
var todos: [Todo] = [] // 待辦列表
var theme: Theme = .light // 主題設置
}
// 子狀態(按需拆分)
struct User {
let id: String
let name: String
let token: String
}
enum Theme {
case light, dark
}
步驟 2:定義 Action(行為指令)
swift
// 全局Action枚舉(按功能拆分)
enum AppAction {
// 用户相關
case login(User)
case logout
// 待辦相關
case addTodo(Todo)
case deleteTodo(id: String)
// 主題相關
case switchTheme(Theme)
}
步驟 3:實現 Reducer(狀態計算)
swift
// 純函數:接收舊狀態+Action,返回新狀態
func appReducer(state: AppState, action: AppAction) -> AppState {
var newState = state // 基於舊狀態創建新狀態(不可變)
switch action {
case .login(let user):
newState.user = user
case .logout:
newState.user = nil
case .addTodo(let todo):
newState.todos.append(todo)
case .deleteTodo(let id):
newState.todos.removeAll { $0.id == id }
case .switchTheme(let theme):
newState.theme = theme
}
return newState
}
步驟 4:實現 Store(狀態倉庫,單例)
swift
final class Store {
static let shared = Store() // 全局單例
private(set) var state: AppState // 私有狀態,僅通過dispatch修改
private init() {
state = AppState() // 初始狀態
}
// 派發Action,觸發狀態更新
func dispatch(action: AppAction) {
state = appReducer(state: state, action: action)
// 通知訂閲者狀態變化(如用NotificationCenter或Combine)
NotificationCenter.default.post(name: .stateDidChange, object: nil)
}
}
步驟 5:頁面訂閲與觸發 Action
swift
// 登錄頁面:觸發Action
class LoginViewController: UIViewController {
func loginSuccess(user: User) {
Store.shared.dispatch(action: .login(user))
}
}
// 個人中心頁面:訂閲狀態變化
class ProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(updateUI),
name: .stateDidChange,
object: nil
)
}
@objc private func updateUI() {
let user = Store.shared.state.user
userNameLabel.text = user?.name ?? "未登錄"
}
}
2. 基於第三方庫 ReSwift(複雜場景)
步驟 1:集成 ReSwift
swift
// Podfile
pod 'ReSwift'
步驟 2:定義 State 和 Action
swift
import ReSwift
struct AppState: StateType {
var user: User?
var todos: [Todo] = []
}
enum AppAction: Action {
case login(User)
case logout
case addTodo(Todo)
}
步驟 3:實現 Reducer
swift
func appReducer(action: Action, state: AppState?) -> AppState {
let state = state ?? AppState()
guard let action = action as? AppAction else { return state }
switch action {
case .login(let user):
return AppState(user: user, todos: state.todos)
case .logout:
return AppState(user: nil, todos: state.todos)
case .addTodo(let todo):
var todos = state.todos
todos.append(todo)
return AppState(user: state.user, todos: todos)
}
}
步驟 4:創建 Store 並訂閲
swift
// 全局Store
let store = Store(
reducer: appReducer,
state: nil,
middleware: [loggingMiddleware] // 可選:中間件(如日誌)
)
// 頁面訂閲狀態
class TodoListViewController: UIViewController, StoreSubscriber {
typealias StoreSubscriberStateType = AppState
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
store.subscribe(self)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
store.unsubscribe(self)
}
// 狀態更新回調
func newState(state: AppState) {
todoTableView.reloadData(with: state.todos)
}
// 觸發Action
func addNewTodo() {
let todo = Todo(id: "1", title: "學習Redux")
store.dispatch(AppAction.addTodo(todo))
}
}
步驟 5:Middleware 處理副作用(如網絡請求)
swift
// 日誌中間件示例
let loggingMiddleware: Middleware<AppState> = { dispatch, getState in
return { next in
return { action in
print("Dispatching action: \(action)")
next(action) // 傳遞Action給下一個中間件/Reducer
print("New state: \(getState()!)")
}
}
}
// 網絡請求中間件(登錄邏輯)
let authMiddleware: Middleware<AppState> = { dispatch, getState in
return { next in
return { action in
if let loginAction = action as? AppAction, case .login(let user) = loginAction {
// 模擬網絡請求
AuthService.login(user: user) { result in
switch result {
case .success(let token):
dispatch(AppAction.saveToken(token)) // 派發後續Action
case .failure:
dispatch(AppAction.loginFailed)
}
}
}
next(action)
}
}
}
三、Redux 在 iOS 中的適用場景與優勢
1. 適用場景
- 全局狀態共享:用户信息、主題設置、多頁面共享的購物車數據等;
- 複雜狀態流轉:如電商下單流程(選品→結算→支付→訂單)、社交 APP 的消息狀態;
- 可回溯 / 調試需求:通過記錄 Action 日誌,復現用户操作路徑(類似 Redux DevTools)。
2. 核心優勢
- 單向數據流:狀態變化可預測,便於調試和定位 Bug;
- 狀態集中管理:避免多頁面傳值混亂(如 Delegate、NotificationCenter 濫用);
- 不可變狀態:通過值類型(Struct)實現狀態不可變,避免多線程數據競爭;
- 純函數 Reducer:無副作用,便於單元測試(輸入確定→輸出確定)。
四、iOS 中 Redux 的侷限性與替代方案
1. 侷限性
- 樣板代碼較多:Action、Reducer 等定義增加代碼量,簡單場景(如單頁面狀態)顯得冗餘;
- SwiftUI 適配:SwiftUI 本身通過
@State/@ObservableObject實現狀態管理,Redux 可作為補充但非必需; - 性能考量:全局狀態更新可能觸發無關頁面刷新(需優化訂閲邏輯)。
2. 替代方案
- SwiftUI 原生狀態管理:
@State/@StateObject/@EnvironmentObject(輕量場景); - Combine+MVVM:通過
PassthroughSubject/CurrentValueSubject實現狀態流轉; - TCA(The Composable Architecture):更貼合 Swift 的函數式狀態管理庫,融合 Redux 思想 + Swift 特性。