1. 框架概述
The Composable Architecture (TCA) 是一个由 Point-Free(Brandon Williams 和 Stephen Celis)开发的开源 Swift 库,专注于以一致、可理解的方式构建 Apple 平台应用(支持 iOS、macOS、iPadOS、visionOS、tvOS 和 watchOS)。它与 SwiftUI、UIKit 等 UI 框架兼容,受到 Elm 架构和 Redux 的启发,但通过 Swift 的类型系统和现代特性(如宏、async/await)进行了深度优化。TCA 的核心目标是提供模块化、可测试、符合人体工程学的应用架构,解决以下问题:
- 状态管理:用值类型(如 struct)管理状态,确保跨视图共享和即时更新。
- 模块组合:将复杂功能拆分为小型、隔离的模块,便于组合和复用。
- 副作用处理:通过
Effect
类型管理异步操作(如网络请求),确保可测试性。 - 测试:支持单元测试、集成测试和端到端测试,覆盖复杂场景。
- 人体工程学:用最少的概念(State、Action、Reducer、Store、Effect)构建简洁 API。
TCA 的设计理念在 Point-Free 的视频系列中逐步完善,文档提到通过多集视频(https://www.pointfree.co/collections/composable-architecture)从头讲解架构,适合深入学习。
2. 核心组件与实现
TCA 的核心围绕五个类型/概念展开,文档提供了清晰的代码示例(见 <DOCUMENT>
),以下进一步总结并补充分析:
- State(状态):
- 用
@ObservableState
宏标记的结构体,描述功能所需数据。例如:swift @ObservableState struct FeatureState: Equatable { var count = 0 var numberFact: String? }
- 使用值类型(struct)避免可变状态的复杂性,
Equatable
确保状态比较高效。 @ObservableState
利用 Swift Observation 框架(Swift 5.9+),自动生成观察逻辑,适合 SwiftUI 视图更新。
- Action(动作):
- 枚举所有可能的交互或事件,如用户操作、通知或 API 响应。例如:
swift enum FeatureAction { case decrementButtonTapped case incrementButtonTapped case numberFactButtonTapped case numberFactResponse(String) }
- 动作是单向数据流的入口,触发 Reducer 执行状态变更。
- Reducer(减速器):
- 用
@Reducer
宏定义,描述如何根据 Action 更新 State 并返回 Effect。例如:@Reducer struct Feature { @ObservableState struct State: Equatable { /* ... */ } enum Action { /* ... */ } @Dependency(\.numberFact) var numberFact var body: some Reducer<State, Action> { Reduce { state, action in switch action { case .decrementButtonTapped: state.count -= 1 return .none case .incrementButtonTapped: state.count += 1 return .none case .numberFactButtonTapped: return .run { [count = state.count] send in let fact = try await numberFact.fetch(count) await send(.numberFactResponse(fact)) } case let .numberFactResponse(fact): state.numberFact = fact return .none } } } }
- Reducer 是 TCA 的核心逻辑单元,确保状态变化确定性,Effect 管理副作用。
- Store(存储):
- 运行时引擎,持有 State,接收 Action,执行 Reducer,驱动 UI 更新。例如:
swift let store = Store(initialState: Feature.State()) { Feature() }
- 在 SwiftUI 中,
StoreOf<Feature>
与视图绑定,自动观察状态变化。
- Effect(效果):
- 表示副作用(如网络请求、定时器),通过
.run
或.none
返回。例如:swift return .run { [count = state.count] send in let fact = try await numberFact.fetch(count) await send(.numberFactResponse(fact)) }
- 支持 Combine 和 async/await,易于取消和测试。
依赖管理:
- TCA 通过
@Dependency
宏和DependencyValues
提供依赖注入。例如,NumberFactClient
封装 API 调用:
struct NumberFactClient: DependencyKey {
var fetch: (Int) async throws -> String
static let liveValue = Self { number in
let (data, _) = try await URLSession.shared.data(from: URL(string: "http://numbersapi.com/\(number)")!)
return String(decoding: data, as: UTF8.self)
}
}
- 测试中可轻松 mock 依赖:
let store = TestStore(initialState: Feature.State()) {
Feature()
} withDependencies: {
$0.numberFact.fetch = { "\($0) is a good number" }
}
3. 最近更新(基于 GitHub Releases 和社区讨论)
根据 GitHub 仓库(截至 2025 年 3 月 31 日,版本 1.20.2)及相关讨论,以下是 TCA 的最新动态:
- Swift 5.9+ 宏支持:引入
@Reducer
和@ObservableState
宏,简化 Reducer 协议和状态观察,减少 boilerplate。例如,1.7.0 版本(2024 年)添加了 Observation 支持(#2593),软弃用旧 API,优化 SwiftUI 集成。 - 并发改进:
- 修复 Store 中 Combine subject 的数据竞争问题(#3447, #3475),提升线程安全。
- 隔离根 Store 的取消操作(#3660),优化 Effect 性能。
- 测试增强:
- 修复 TestStore 的问题,如忽略新属性包装器(#3666)。
- 改进动态 Ascertain autocomplete(#3463),提升测试体验。
- 导航工具:计划在 1.0 版本前完善导航支持,适配 SwiftUI 3.0+ 的栈导航(#1477)。
- 模块化示例:社区贡献了模块化应用的样例项目(#3173),展示如何在多目标(iOS/macOS)中共享模块,解决 Xcode SPM 缓存问题。
- Swift 6 支持:支持 Swift 6 语言模式和严格并发检查(#3173),确保未来兼容性。
这些更新表明 TCA 持续优化性能、并发和开发者体验,尤其在 Swift 生态的最新特性(如宏、Observation)上保持领先。
4. 优缺点分析
优点:
- 模块化:支持功能拆分和组合,适合大型项目。例如,isowords 游戏(https://github.com/pointfreeco/isowords)展示了复杂应用的模块化实现。
- 测试性:
TestStore
支持 exhaustive 测试,覆盖状态变化和 Effect。例如:
@Test
func testFeature() async {
let store = TestStore(initialState: Feature.State()) {
Feature()
} withDependencies: {
$0.numberFact.fetch = { "\($0) is a good number" }
}
await store.send(.incrementButtonTapped) { $0.count = 1 }
await store.send(.numberFactButtonTapped)
await store.receive(\.numberFactResponse) { $0.numberFact = "1 is a good number" }
}
- 副作用管理:Effect 使异步操作可控、可测试,优于传统的闭包回调。
- 跨平台:支持所有 Apple 平台,兼容 SwiftUI 和 UIKit。
- 社区活跃:191 位贡献者、1270 个 PR、1200+ GitHub 讨论,社区支持强大(如 TCACoordinators、TCAComposer 等扩展库)。
缺点:
- 学习曲线:概念(如 Reducer、Effect)对新手稍复杂,需熟悉单向数据流。社区反馈早期 TCA 使用复杂,但最新更新(宏、教程)已降低门槛。
- Boilerplate:尽管宏减少了样板代码,某些场景仍需较多代码(如私有 Action 封装需额外 struct)。社区建议未来用宏进一步简化。
- 性能:值类型和观察机制高效,但大型 State 需小心管理内存(Swift 编译器优化已缓解此问题)。
- 依赖管理:需手动注册依赖(如
NumberFactClient
),可能在复杂项目中增加维护成本。
5. 实际应用场景
TCA 适用于需要强壮架构的复杂应用,尤其在以下场景:
- 大型项目:如 isowords(字谜游戏),展示了 TCA 在导航、状态共享和副作用中的能力。
- 跨平台开发:支持多平台模块共享(#3173),适合 iOS/macOS 混合项目。
- 高测试覆盖:如 Primer 和 Zines 应用,利用 TCA 的测试工具实现低成本、高覆盖测试。
- 实时应用:通过 Effect 和 Observation,支持实时状态更新,适合动态 UI(如 SwiftUI 视图)。
社区案例:
- Life Progress 应用(https://github.com/Bartozo/Life-Progress-iOS):使用 TCA 的最新 Reducer 协议,展示了现代化特性。
- Tic-Tac-Toe 示例:展示模块化设计和 SPM 集成。
6. 安装与使用
安装:
- Xcode → File → Add Package Dependencies…
- 输入 URL:https://github.com/pointfreeco/swift-composable-architecture
- 选择目标:
最低要求:
- Swift 5.10+
- iOS 15+、macOS 12+ 等
文档与学习资源:
- 官方文档:https://pointfreeco.github.io/swift-composable-architecture/
- 交互式教程:Meet the Composable Architecture(DocC 格式)。
- 示例目录:包含计数器、语音备忘录、待办列表等。
- Point-Free 视频:深入讲解 TCA 的设计与实现(https://www.pointfree.co/collections/composable-architecture)。
7. 社区与生态
- 活跃社区:1.5k forks、13.4k stars,116 个 release,57,000+ Slack 消息。
- 讨论平台:
- GitHub Discussions(https://github.com/pointfreeco/swift-composable-architecture/discussions)
- Swift 论坛(https://forums.swift.org/c/related-projects/swift-composable-architecture)
- Point-Free Slack 社区
- 扩展库:
- Composable Architecture Extras:增强功能。
- TCAComposer:生成样板代码的宏框架。
- TCACoordinators:支持 Coordinator 模式。
- 贡献:欢迎 PR 提交新库或翻译(如 README 的多语言版本)。
8. 与其他架构的对比
TCA 基于 Elm 和 Redux,但更适配 Swift:
- 比 Elm:更灵活的 Effect 系统,集成 Swift 的类型安全和并发特性。
- 比 Redux:更严格的副作用管理(强制用 Effect),减少运行时错误。
- 比 MVVM:更强的测试性和模块化,适合复杂应用,但可能比轻量 MVVM 多 boilerplate。
9. 结论与推荐
TCA 是一个功能强大、现代化的 Swift 架构,适合需要高可维护性、可测试性和模块化的项目。最新更新(1.20.2)通过宏和并发优化显著降低了使用门槛,尤其适合 SwiftUI 项目。社区活跃,资源丰富(如 isowords、DocC 教程),是 Apple 开发者构建复杂应用的理想选择。缺点(如学习曲线)正通过宏和文档改进逐步缓解。
推荐场景:
- 大型、长期维护的 iOS/macOS 应用。
- 需要高测试覆盖率的团队项目。
- 跨平台、模块化开发的复杂场景。
建议: