mcpField
S
swift-architecture

swift-architecture

github.com/dpearson2699开发1.2k3.1k 次安装13 周前更新
代码仓库

关于 swift-architecture

swift-architecture 是面向 Swift 开发的架构选择与迁移技能,帮助开发者根据状态、依赖和副作用等实际需求选择合适模式。它默认建议简单的 SwiftUI 功能采用 MV,并提供逐步升级和测试指导。

主要功能

  1. 01按实际复杂度选择架构模式
  2. 02以 MV 作为 SwiftUI 默认起点
  3. 03明确状态所有者与依赖边界
  4. 04规划按功能切片的渐进迁移
  5. 05通过状态与依赖失败测试验证

适用场景

  1. 01为新 SwiftUI 功能选择架构
  2. 02判断何时从 MV 升级到 TCA
  3. 03逐步迁移既有功能边界
  4. 04检查依赖注入与状态转换设计

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swift-architecture

安装后在 Claude Code 中输入/swift-architecture确认已加载。

附带文件evals/evals.jsonreferences/architecture-patterns.md

详细介绍

Swift 架构

选择能明确状态归属、依赖、副作用和测试的最小架构。新的 SwiftUI 功能默认采用 MV;只有在观察到复杂性时才升级。

目录

范围边界

本指南负责模式选择、模块边界、依赖方向、迁移策略以及架构层面的测试接缝。SwiftUI 属性包装器的连接方式和视图组合请参阅 swiftui-patterns,导航 API 和路由模型请参阅 swiftui-navigation,隔离诊断请参阅 swift-concurrency,测试语法和测试固件请参阅 swift-testing。

决策流程

  1. 记录功能的状态归属者、输入、输出、依赖、副作用、导航交接方式以及现有测试。
  2. 找出具体压力:复杂状态机、共享派生状态、依赖控制、功能组合、团队所有权或 UIKit 导航。
  3. 选择能应对该压力的最小模式;记录它增加了什么,以及哪些内容保持不变。
  4. 使用注入的依赖和可观察的状态转换,实现一个垂直切片。
  5. 运行现有行为测试,以及状态转换和依赖故障测试。如果行为发生变化,恢复测试固件,修复最小边界,然后重新运行测试,再迁移另一个切片。

模式选择

模式适用场景主要代价
MVSwiftUI 功能的状态和编排都比较简单如果不拆分,逻辑可能会逐渐堆积在大型视图中
MVVM表现逻辑需要一个可独立测试的适配器额外层可能沦为单纯转发的壳
MVI最适合将功能建模为显式的状态 + 意图 + reducer/effects样板代码,以及集中式转换设计
TCA多个可组合功能都需要确定性 effects、依赖和测试框架学习成本和架构层面的承诺
Clean Architecture大型产品需要在 domain/data/UI 之间严格控制依赖方向协议和映射的额外开销
CoordinatorUIKit 或混合导航需要独立的流程归属者多一个生命周期和路由归属者
VIPER维护已有且采用成熟 VIPER 边界的 UIKit 模块形式繁琐;不适合作为新 SwiftUI 功能的默认方案

如果压力来自导航复杂性,可将 Coordinator 与另一种状态模式搭配使用;它不能替代 domain/state 架构。

MV 默认方案

让视图表达状态,并将业务操作放入可观察模型和注入的服务中:

@MainActor
@Observable
final class TripStore {
    private let client: TripClient
    var trips: [Trip] = []
    var error: Error?

    init(client: TripClient) { self.client = client }

    func load() async {
        do { trips = try await client.fetchTrips() }
        catch { self.error = error }
    }
}

struct TripList: View {
    @State private var store: TripStore

    init(client: TripClient) {
        _store = State(initialValue: TripStore(client: client))
    }

    var body: some View {
        List(store.trips) { Text($0.name) }
            .task { await store.load() }
    }
}

加载 架构模式方案,查看 MVVM、MVI、TCA、Clean Architecture、Coordinator 和 VIPER 的结构。

升级信号

  • 当大量表现转换必须在不渲染视图的情况下进行测试,且适配器确实包含行为时,选择 MVVM。
  • 当转换、无效状态和 effects 需要一条可审计的 reducer 式路径时,选择 MVI。
  • 当多个模块反复需要功能组合、依赖覆盖、取消以及确定性的 effect 测试时,选择 TCA。
  • 当多个交付层/数据层之间需要独立的 domain 规则和依赖方向时,选择 Clean Architecture。
  • 当 UIKit/混合导航需要明确路由归属、复杂流程组合,或需要在视图控制器之外进行条件导航时,添加 Coordinator。
  • 对兼容的旧版模块或有意进行的迁移保留 VIPER;不要仅因习惯而用它启动新的 SwiftUI 功能。

不要仅仅因为视图很长就升级架构。应先提取子视图、服务和职责明确的可观察模型。

迁移

每次迁移一个功能边界:

  1. 通过测试和依赖项/状态清单固定现有行为。
  2. 在现有操作外围引入目标边界。
  3. 一次迁移一个状态转换或依赖项,不要同时重写 UI 和持久化逻辑。
  4. 每完成一部分,就比较行为、导航、取消、错误和持久化结果。
  5. 只有在没有调用方或测试依赖旧路径后,才移除它。

从 ObservableObject 迁移到 Observation 时,在替换包装器之前,先保持相同的所有者和变更隔离。从 MVVM 迁移到 MV 时,只有在视图已绑定到相同的模型/服务行为后,才删除仅用于转发的视图模型成员。采用 TCA 时,先封装一个功能的状态/操作/效果,再逐步迁移依赖项。

常见错误

错误修正方法
因为某种模式流行而选择它根据观察到的功能压力来选择。
视图模型只转发属性移除它,改用 MV。
一个对象同时负责导航、网络、格式化、持久化和 UI 状态按职责和依赖方向拆分。
在简单屏幕上套用 TCA 或 Clean Architecture从 MV 开始,并保留升级空间。
将 Coordinator 用作状态架构让它专注于路由/生命周期的所有权。
在一个功能中混用多种模式定义一种局部状态/效果模型,并在功能边界处迁移。
一次性大规模迁移每次迁移一个经过测试的纵向切片,并重新运行同一套验证矩阵。

审查清单

  • 选择依据具体的功能/团队压力给出说明
  • 明确状态所有者、变更路径、依赖项、效果和导航所有者
  • 注入依赖项,使其可在测试中替换
  • 模式成本与功能复杂度相称
  • UI 机制、导航 API、隔离和测试语法转到相关的技能文档
  • 每次迁移一个纵向切片,并保留现有行为
  • 每次迁移后,验证失败、取消、导航和持久化行为
  • 不留仅用于转发的层或上帝对象

参考资料

评论

支持 Markdown