ProgressReporter

一种高度抽象的方法,用于协调来自多个对象的输入,以跟踪单个复杂任务的进度。

为什么需要它?

实际上没什么特别的。如果你的项目使用 Swift,并且有复杂或长时间运行的任务,不妨试试这个。也许你就不需要重复造轮子了。 我在自己的项目中用它来处理网络操作、Core Data 迁移以及复杂的数据任务……基本上任何用户需要看到进度条的事情。

NSProgress 呢?

NSProgress 可以用,而且效果很好。但是,它是用 Objective-C 为 iOS 7 编写的,并且使用了 KVO。坦率地说,虽然它有一些很棒的技巧(例如与 Core Data 直接集成),但对于我的需求来说,它过于复杂了。这个工具简单、直接、轻量级。

@ObservableObject / Combine 支持

在最新版本的 ProgressReporter 中,你可以将 ProgressCoordinator 设置为 SwiftUI 视图中的 @ObservedObject。这将允许你使用 .onReceive 立即更新你在视图中创建的任何进度指示器。这又是放弃 NSProgress 而选择 ProgressReporter 的另一个理由

progress 变量会发布到任何订阅的视图。因此,你将能够创建漂亮的进度更新器,可以同时显示多个数据点(例如,剩余估计时间、动画、倒计时、进度条等)。

安装

只有一个文件。你可以将它拖放到你的项目中,并在需要时使用。或者,如果你觉得想偷懒/奢侈一把,可以使用 Swift Package Manager。

开始使用

内联文档非常详细且有帮助,但如果你不确定从哪里开始,这里有一个概要

大多数用例

  1. 创建一个 ProgressCoordinator,并在需要报告进度的地方使用 shared 实例。
  2. 使视图或控制器遵循 ProgressWatcher 协议,然后在你的 Coordinator 上设置 watcher 对象。
  3. 使用 addStepsToProgress 根据需要向 Progress 对象添加尽可能多的步骤。
  4. 每次完成一个“步骤”时,调用你的共享实例上的 reportProgress
  5. 就是这样。每次更新发生时,都会在你的 ProgressWatcher 上调用 hasProgressToReport。检查 Progress 结构体的 progress 值,它是一个介于 0.0 和 1.0 之间的浮点数。非常适合 UIProgressView

SwiftUI 实现

  1. 使用 shared 实例创建一个 ProgressCoordinator,并在你的视图上将其声明为 ObservableObject
    @ObservedObject var progressCoordinator = ProgressCoordinator.shared
  2. 显示进度信息的视图应该像这样实现 .onReceive() 修饰符
    .onReceive(progressCoordinator.$rawProgress, perform: { progress in
        // Do what you need to update your views here. For example,
        // progressValue could be an @State object bound to some other view.
        self.progressValue = progress
    })
  3. 使用 addStepsToProgress 根据需要向 Progress 对象添加尽可能多的步骤。
  4. 每次完成一个“步骤”时,调用你的共享实例上的 reportProgress
  5. 就是这样。每次更新发生时,都会在你的 ProgressWatcher 上调用 hasProgressToReport。检查 Progress 结构体的 progress 值,它是一个介于 0.0 和 1.0 之间的浮点数。

更复杂的情况

共享实例模型可能不适合你。你可以简单地避免访问 shared 实例,并以你自己的方式初始化。

或者,你可以继承 ProgressCoordinator 或实现 ProgressCensus 协议。无论哪种方式,你的灵活性都会大大提高。实现该协议的缺点(或潜在的好处)是,你必须自己执行进度计算。