Administrator
发布于 2026-02-26 / 4 阅读
0
0

AIChats 数据架构完整设计(SwiftUI + VIPER + SwiftData)

1️⃣ AIChats 完整数据流

先看最终数据流:

Network
   ↓
DTO / NetworkModel (Codable)
   ↓
Cache (Disk / Memory / TTL)
   ↓
Domain Model (struct, Sendable)
   ↓
Interactor / Presenter
   ↓
SwiftUI View State
   ↓
Persistence Entity (@Model class)


■ 每一层职责


① NetworkModel(DTO)

特点:

  • Codable

  • 与接口强绑定

  • 不参与业务逻辑

  • 不直接进入 UI

struct ChatMessageDTO: Codable {
  let id: String
  let content: String
}


② Cache 层

解决:

  • 首屏速度

  • 离线恢复

  • streaming snapshot

  • TTL 过期策略

你之前的本地优先策略正是这一层。


③ Domain Model(核心)

这是整个架构的中心。

特点:

  • struct

  • Sendable

  • Hashable

  • 可被 UI 安全持有

  • 不依赖存储框架

struct ChatMessage: Identifiable, Sendable, Hashable, Codable {
  var id: String
  var content: String
}


④ Interactor / Presenter

职责:

  • 网络 + 缓存协调

  • 业务逻辑

  • streaming 管理

  • optimistic UI

这里不应该出现 SwiftData Entity


⑤ UI 层

SwiftUI 只消费 Domain。

避免:

  • SwiftData 泄漏

  • 引用语义污染

  • 并发风险


⑥ Persistence(SwiftData)

只负责:

  • 查询

  • 存储

  • 关系

  • change tracking


2️⃣ SwiftUI + VIPER 中 Model 的最佳分层

这是你现在 AIChats 最推荐结构:

Modules/Chat/
 ├── DTO/
 ├── Domain/
 ├── Entity/
 ├── Mapper/
 ├── Repository/
 ├── Interactor/
 ├── Presenter/
 └── View/


■ DTO

只做接口映射。


■ Domain

真正业务数据。

Interactor / Presenter / UI 全部使用。


■ Entity

SwiftData / CoreData / Realm 绑定。

永远不要直接给 UI。


■ Mapper

DTO ↔ Domain

Entity ↔ Domain


■ Repository

整合:

  • Network

  • Cache

  • Persistence

输出 Domain。


3️⃣ 如何避免 SwiftData 污染 Domain(关键)

这是很多项目后期崩溃的原因。


❌ 错误做法

UI 直接持有:

@Query var messages: [ChatMessageEntity]

问题:

  • 引用语义污染 UI

  • actor 不安全

  • diff 不稳定

  • 测试困难

  • 数据库替换困难


✅ 正确做法

Repository 输出 Domain:

func fetchMessages() async -> [ChatMessage]

Interactor / Presenter 持有 Domain。

UI 只绑定 Domain。


■ Mapper 是关键隔离层

extension ChatMessageEntity {
  func toDomain() -> ChatMessage {
    ChatMessage(id: id, content: content)
  }
}


4️⃣ 为什么这种架构对 AIChats 特别重要

你的项目具有:

  • streaming message

  • optimistic UI

  • 本地优先缓存

  • AI token streaming

  • timeline UI

  • 并发任务很多

这些都要求:

👉 值语义稳定

👉 UI snapshot 稳定

👉 actor 安全

SwiftData Entity 无法满足。


5️⃣ struct + class 的黄金职责划分

struct

  • DTO

  • Domain

  • Cache snapshot

  • View state


class / actor

  • Service

  • Manager

  • Store

  • Router

  • SwiftData Entity


6️⃣ 未来扩展能力(双模型的最大价值)

采用该架构后:

  • 可替换 SwiftData

  • 可引入 CloudKit

  • 可做 event sourcing

  • 可做 timeline snapshot

  • 可做 message replay

  • 可做离线 AI cache

对 AIChats 非常关键。


⭐ 最终总结

数据流

Network → Cache → Domain → UI → Persistence


分层原则

DTO / Domain / Entity 三层隔离


SwiftUI 原则

UI 永远只持有 struct Domain


SwiftData 原则

Entity 仅用于存储,不进入业务与 UI



如果你愿意

我可以继续帮你写下一篇进阶(强烈建议):

👉 AIChats Repository 设计(本地优先 + streaming + diff)

👉 AsyncStream 在数据层的最佳用法

👉 如何让 Presenter 不持有 SwiftData 也能实时更新 UI

👉 SwiftData + AsyncStream 的组合方案(非常高级)

这一套会直接让你的 AIChats 架构到达可产品化级别


评论