Skip to content

Latest commit

 

History

History
60 lines (34 loc) · 3.9 KB

architecture.md

File metadata and controls

60 lines (34 loc) · 3.9 KB

架构

采用如下图所示的MVVM架构。

Model

Model 部分的实现细节详见 model-detail.md

Model 部分主要进行缓存的管理,以及向服务器请求和发送数据。如上图所示,Request 进行具体的请求(查询缓存/进行HTTP请求),Request PublisherRequest 进行包装,并向 View Model 提供声明式的接口。

缓存管理

第三方依赖库:

请求和发送数据

我们为与树洞后端进行通信的类型定义了一个协议 Request 以规定接口,同时实现代码的高效复用。所有请求均可抽象成遵循此协议的类型。对于大部分请求而言,其请求过程均为请求数据 - 解析JSON - 数据转换 - 返回数据。针对这些请求,我们在 Request 的基础上规定了一个更高级的协议 DefaultRequest,并为其请求过程进行了默认的实现,大大减少了重复代码的编写。

Publisher

针对声明式代码,利用原生 Combine 框架,我们使用 Publisher 对 Request 进行包装,降低管理异步事件的难度,同时更好地与 SwiftUI 的声明式风格融合。所有 Request 均可获取其 publisher,并在收到订阅时进行请求并返回结果。

View

View 部分的实现细节详见 view-detail.md

数据流

View 部分的主要难点是数据流的实现。根据设计,本应用的数据流有以下几类:

  • 整个应用的数据共享
  • 父 View 与子 View 绑定数据
    • 父 View 作为唯一数据源
    • 子 View 作为(暂时的)唯一数据源
  • 父 View 向子 View 传递只读数据

整个应用的数据共享

由于采用了 SwiftUI 的生命周期(App Essentials in SwiftUI),我们定义一个表示应用状态的类型 AppModel,在 HollowApp 中监测其变化,在其他位置通过修改单例实现数据共享。

父 View 与子 View 绑定数据 / 传递只读数据

当子 View 需要修改数据源(而本身并不拥有数据)时,用 @Binding 进行数据绑定;否则直接进行值的传递,此时父 View 中的数据对于子 View 来说是只读的。

子 View 作为(暂时的)唯一数据源

有些情况下,子 View 需要更新父 View 中的数据,然而父 View 本身在这个过程中也可能会更新数据,从而导致很多问题。在某些情况下,我们需要在子 View 存在的时间里,将子 View 的数据作为唯一的数据源:子 View 中的数据不受父 View 的影响,并在自身的数据更新后,对父 View 的数据进行更新。

使用 UIKit

在本应用的实现中,有三种使用 UIKit 框架的情况:

  • UIKit 的 UIViewUIViewController 作为 View,通过 UIViewRepresentableUIViewControllerRepresentable 实现。
  • 先将 ViewUIHostingController 包装为 UIKit 的 UIViewController,在对其内部进行一定修改后,再用 UIViewControllerRepresentable 包装为 View
  • 直接使用 UIKit 的命令式代码实现视图的导航等操作。