返回

解决 SwiftUI 中 `.refreshable()` 旋转指示器无限旋转问题

IOS

SwiftUI 中的 .refreshable() 问题以及解决方案

简介

在 SwiftUI 中使用 .refreshable() 时,如果刷新操作的异步逻辑没有及时完成或没有正确更新 UI,旋转指示器可能会无限期地旋转。本文将探讨此问题的可能原因并提供几种有效的解决方案。

问题

.refreshable() 函数中的刷新逻辑触发异步操作时,旋转指示器会一直显示,直到异步操作完成并更新 UI。然而,如果异步操作没有及时完成或没有正确更新 UI,旋转指示器就会无限期地旋转。

原因

此问题的发生是因为 .refreshable() 函数中的刷新逻辑没有及时更新 UI。当异步操作被触发时,UI 将保持其当前状态,直到操作完成并更新 UI。如果异步操作没有及时完成或没有正确更新 UI,旋转指示器就会无限期地旋转。

解决方案

要解决此问题,有几种可能的解决方案:

1. 使用 .onReceive() 监听查询更新

可以使用 .onReceive() 监听查询更新,然后在更新收到后手动关闭旋转指示器:

struct ContentView: View {
  @State private var isRefreshing = false
  @State private var query: Query

  var body: some View {
    List() {
      // items ...
    }
    .refreshable {
      isRefreshing = true
      await query.refetchAsync()
    }
    .onReceive(query.updates) { _ in
      isRefreshing = false
    }
  }
}

2. 使用 .task() 执行异步刷新

也可以使用 .task() 将异步刷新逻辑移出 .refreshable() 函数:

struct ContentView: View {
  @State private var isRefreshing = false
  @State private var query: Query

  var body: some View {
    List() {
      // items ...
    }
    .refreshable {
      isRefreshing = true
    }

    .task {
      await query.refetchAsync()
      isRefreshing = false
    }
  }
}

3. 在刷新逻辑中更新 UI

如果刷新逻辑是在 .refreshable() 函数之外执行的,则需要在刷新完成后手动更新 UI。例如,可以使用 .refreshable() 来触发刷新操作,然后在另一个 .onAppear().onChange() 修饰符中更新 UI:

struct ContentView: View {
  @State private var isRefreshing = false
  @State private var query: Query

  var body: some View {
    List() {
      // items ...
    }
    .refreshable {
      isRefreshing = true
    }

    .onAppear {
      Task {
        await query.refetchAsync()
        isRefreshing = false
      }
    }
  }
}

4. 确保异步操作完成

确保异步刷新逻辑能够及时完成。这意味着刷新操作应该在合理的时间内完成,并且不应无限期地阻塞 UI 线程。考虑使用异步库或 Task 来管理异步操作。

提示

  • 检查刷新逻辑是否正确处理了错误,并根据需要更新 UI。
  • 使用断点和日志来调试刷新逻辑并识别任何潜在问题。
  • 优化异步操作,确保它们及时完成并不会阻塞 UI 线程。

结论

通过了解 .refreshable() 函数的行为并采用适当的解决方案,可以解决 SwiftUI 中旋转指示器无限期旋转的问题。通过使用 .onReceive(), .task(), 或手动更新 UI,可以确保刷新逻辑及时完成并更新 UI,从而提供最佳的用户体验。

常见问题解答

1. 为什么我的旋转指示器在刷新后不会关闭?

可能是因为异步刷新逻辑没有及时完成或没有正确更新 UI。

2. 如何使用 .onReceive() 监听查询更新?

.onReceive() 修饰符附加到查询的更新发布器,并在收到更新时手动关闭旋转指示器。

3. 如何使用 .task() 执行异步刷新?

.task() 修饰符附加到 SwiftUI 视图,并在其中执行异步刷新逻辑,然后在操作完成后手动关闭旋转指示器。

4. 如何在刷新逻辑中手动更新 UI?

.refreshable() 函数之外执行刷新逻辑,并在操作完成后使用 .State 变量或其他 UI 更新机制手动更新 UI。

5. 如何确保异步操作及时完成?

使用异步库或 Task 来管理异步操作,并优化代码以确保它们在合理的时间内完成并不会阻塞 UI 线程。