SwiftUI 在批量文件上传期间显示刷新进度

SwiftUI display refresh progresses during batch files uploading

上下文(macOS 应用程序): 用户可以 select 一堆图像,然后,我开始并行地一次至少上传 5 个文件。问题是我想显示从服务器接收到的每个图像的进度。我对该数组使用 @State 指标来观察变化。 进度状态可以是:待处理、进行中 (%) 和完成。 我需要显示每张图片的百分比。

问题: 进度更新非常频繁,我需要在 ScrollView 中反映这些更改。 图像的布局显示为网格视图(正方形显示),但这会导致 3 个问题:

  1. var body: some View { ... } 每秒调用 2 - 3 次
  2. 滚动视图在所有这些刷新过程中卡住
  3. 如此多的视图刷新也导致内存飙升至 1GB 上传完成后,内存恢复到正常水平 (50 - 70mb)

我什至尝试用计时器更新视图,每秒仅反映一次更改,但这并没有太大帮助。

为了改进渲染,我为每个网格视图和滚动视图添加了 .id(),我可以看到资源使用方面的小改进,但对用户来说感觉还不够好。

我的问题很简单,使用 SwiftUI (1.0) 的最佳实践是什么 - 我们还需要支持 macOS 10.15,而不仅仅是 macOS 11 - 要实现这种 UX,您可以在其中看到进度正在上传文件,但您仍然可以滚动查看待处理的文件或已上传的文件。

由于您没有提供任何代码,因此很难真正深入研究,但这里有几点需要考虑:

  1. 调用 var body: some View { ... } about 2 - 3 times per second 本身不应成为瓶颈。我有 SwiftUI 代码,它以每秒 60 次刷新的速度运行而没有打嗝。然而,它 一个指标,表明 body 调用中的某些东西是昂贵的。 (没有代码无法判断)

  2. 尽可能使用 Equatable -- 尤其是对于昂贵的视图。这将确保在不需要时不会重新呈现昂贵的视图。如果您只有一个视图的一部分是昂贵的,那么值得将其重构为自己的视图以成为 Equatable。更多阅读:https://www.hackingwithswift.com/example-code/language/how-to-conform-to-the-equatable-protocol

  3. 您的数据模型可以重构为 ObservableObjectStateObjectPublisher,您可以在其中使用 Combine 做一些巧妙的事情来减慢速度更新。首先想到的是使用 throttle 来确保您发布的更新仅以 X 间隔反馈到您的视图中。更多阅读:https://rhonabwy.com/2019/12/15/combine-throttle-and-debounce/

  4. 确保您的上传工作是在后台线程上完成的,并且您的 UI 更新是在主线程上进行的。根据您进行上传的方式,Combine 可能会再次帮助您,让您在更新进入时连续回调主线程(也可能没有 Combine,但 Combine 使事情变得非常简单)。更多阅读:http://trycombine.com/posts/subscribe-on-receive-on/

  5. 打开 Instruments,看看是什么造成了您所看到的所有内存使用。这应该会提示您在哪里进行分配以及在哪里进行优化。

最后,SwiftUI List 在 Catalina 上的表现充其量是值得怀疑的。在大苏尔更好。在 SwiftUI 2.0 中,您可以更多地依赖 LazyVStack 之类的东西,但这不是针对 Catalina 的解决方案。如果你真的绝望了,你可以回到 AppKit 并在那里制作你的列表,将它包装在 NSViewRepresentable