Xcode — SwiftUI VIPER 架构

SwiftUI VIPER Architecture 是一种将 VIPER 架构模式(View-Interactor-Presenter-Entity-Router)应用于 SwiftUI 的开发方式。VIPER 是一种模块化的架构设计模式,其目的是将项目逻辑分离,不同责任模块各司其职,从而提升代码的可维护性、可扩展性和测试能力。

这种架构与 SwiftUI 的组合可能显得不太直观,因为 SwiftUI 的设计哲学更偏向于简单和声明式的编程模式,而 VIPER 却是一种更为正式且复杂的架构。结合 SwiftUI 与 VIPER 能够帮助开发者更清晰地划分职责模块,同时仍能保持 SwiftUI 的高效开发特性。

以下是对 SwiftUI 中 VIPER 架构 的详细讲解。


VIPER 是什么? #

VIPER 是一种架构模式,名字由以下 5 个核心部分构成:

  1. View(视图):

    • 用户界面,用于展示 UI,接收用户输入并将事件传递到 Presenter
    • 在 SwiftUI 中,View 是一个 SwiftUI 的声明式视图结构,如 ContentView
  2. Interactor(交互器):

    • 负责业务逻辑和数据处理,处理来自 Presenter 的请求。
    • 从数据层(例如网络请求或本地数据库)获取数据,并将数据返回给 Presenter
  3. Presenter(展示逻辑):

    • 中间层,负责将 Interactor 的处理结果转换为适合 View 使用的数据。
    • 同时处理用户交互事件,并将其转发到 Interactor,然后将反馈返回给 View
  4. Entity(实体):

    • 应用程序中的核心模型(数据结构),通常是数据存储或数据定义类型。
    • 它是纯粹的模型类,通常不直接与视图交互。
  5. Router(路由器):

    • 负责模块之间的导航逻辑。
    • 在 SwiftUI 中,Router 通常处理视图之间的导航,例如 NavigationLinkSheetFullScreenCover

为什么将 VIPER 用于 SwiftUI? #

SwiftUI 的核心思想是使用 StateBinding 在 UI 和数据之间建立声明式绑定关系。从理论上讲,较小的应用可以非常简单地通过 MVVM(Model-View-ViewModel)来实现。然而,当应用变得复杂时,SwiftUI 项目可能会出现逻辑与用户界面混杂在一起的问题。VIPER 的引入可以解决以下问题:

  1. 清晰的模块分离

    • 将视图、业务逻辑、数据管理及路由逻辑完全独立,避免非职责代码混杂。
  2. 便于测试

    • VIPER 的独特分层设计使单元测试更容易(例如单独测试 InteractorPresenter)。
  3. 扩展性强

    • 随着组件模块的增多,VIPER 架构可以帮助在大型项目中管理逻辑,尤其是多模块场景。
  4. 更好的代码复用性

    • 业务逻辑清晰地被抽象并分离,跨模块复用组件变得更加容易。

SwiftUI 上的 VIPER 结构 #

以下是 SwiftUI 中结合 VIPER 的模块设计流程。


1. View: 视图 #

视图负责定义用户界面,并接收用户的输入。它会调用 Presenter 来获取 UI 所需的数据,同时将用户的事件转发给 Presenter

示例代码: #

struct TodoListView: View {
    @ObservedObject var presenter: TodoListPresenter

    var body: some View {
        VStack {
            List(presenter.todos) { todo in
                Text(todo.title)
            }
            Button("Add Todo") {
                presenter.addNewTodo()
            }
        }
    }
}
  • 使用 @ObservedObject 绑定 Presenter,让视图能够根据数据变化自动更新。

2. Interactor: 业务逻辑 #

Interactor 负责处理应用的核心业务逻辑,例如与远程 API 交互或从数据库读取本地数据。

示例代码: #

class TodoListInteractor {
    private var todoRepository: TodoRepository

    init(todoRepository: TodoRepository) {
        self.todoRepository = todoRepository
    }

    func fetchTodos() -> [Todo] {
        return todoRepository.getTodos()
    }

    func createTodo(title: String) {
        todoRepository.addTodo(Todo(title: title))
    }
}
  • 这里的 TodoRepository 是数据源。
  • Interactor 是一种纯粹的业务逻辑实现,它把输入和输出传递给 Presenter

3. Presenter: 数据适配器 #

Presenter 是视图和交互器之间的中介。它负责获取来自 Interactor 的数据,并将这些数据转化为适合 View 显示的格式。

示例代码: #

class TodoListPresenter: ObservableObject {
    @Published var todos: [Todo] = []

    private var interactor: TodoListInteractor

    init(interactor: TodoListInteractor) {
        self.interactor = interactor
    }

    func loadTodos() {
        self.todos = interactor.fetchTodos()
    }

    func addNewTodo() {
        interactor.createTodo(title: "New Task")
        loadTodos()
    }
}
  • PresenterInteractor 的数据公开为通过 @Published 修饰的可观察数据,通知 View 更新。

4. Entity: 数据模型 #

实体是核心数据结构,无需关于应用操作逻辑的任何关系。

示例代码: #

struct Todo: Identifiable {
    let id = UUID()
    let title: String
}
  • Entity 是简单的 structclass,仅代表应用的数据。

5. Router: 路由导航 #

Router 负责页面之间的导航和跳转逻辑。例如,用户点击按钮后跳转到详情页,Router 会负责将这个操作连接到相应的模块。

示例代码: #

class TodoListRouter {
    func navigateToDetailView(todo: Todo) -> some View {
        return TodoDetailView(todo: todo)
    }
}
  • Router 将负责具体的视图切换,如在 SwiftUI 中使用 NavigationLinkSheet

完整示例架构整合 #

假设一个简单的待办事项列表应用,展示整个 SwiftUI VIPER 模块的关系。

  1. TodoListView(View)负责展示任务列表,并绑定 TodoListPresenter
  2. TodoListPresenter(Presenter)控制视图状态变化。
  3. TodoListInteractor(Interactor)执行数据库读取/写入操作。
  4. Todo(Entity)是任务的数据结构。
  5. TodoListRouter(Router)处理页面切换,例如点开任务详情页。

VIPER 优势与挑战 #

优势#

  1. 代码组织清晰
    • 各个模块职能划分明确,便于维护和扩展。
  2. 高可测试性
    • VIPER 的各层都可以独立测试,例如测试 Interactor 的业务逻辑或 Presenter 的数据绑定。
  3. 复用组件
    • 模块高度解耦,InteractorPresenter 等组件很容易在多个页面中复用。
  4. 复杂应用适配
    • 非常适合大型项目或包含复杂业务逻辑的应用。

挑战#

  1. 开发成本高
    • VIPER 的模块划分会带来比其他架构更多的样板代码,对于小型应用可能显得过于复杂。
  2. 学习门槛
    • 对初学者来说,SwiftUI 的声明式开发显得简单易用,而引入 VIPER 增加了复杂度。
  3. SwiftUI 的显式约束
    • SwiftUI 的声明性哲学与 VIPER 的分层思想可能会产生冲突。

总结 #

在 SwiftUI 中应用 VIPER 是一种模块化、职责清晰的架构选择,非常适合大型、复杂的项目开发,但对于小型或简单应用可能显得过于笨重。

如果你:

  1. 项目复杂 —— 使用 VIPER 是更优选择。
  2. 项目简单 —— 考虑更轻量的 MVVM 架构。
本文共 2127 字,上次修改于 Feb 9, 2025
相关标签: Xcode