【问题标题】:onReceive in SwiftUI view causes infinite loopSwiftUI 视图中的 onReceive 导致无限循环
【发布时间】:2020-05-07 21:52:26
【问题描述】:

在一个 SwiftUI 应用程序中,我有一个 ObservableObject 来跟踪用户设置:

class UserSettings: ObservableObject {
    @Published var setting: String?
}

我有一个视图模型来控制我的视图的状态:

class TestViewModel: ObservableObject {
    @Published var state: String = ""
}

我有我的看法。当用户设置改变时,我想让视图模型更新视图的状态:

struct HomeView: View {
    @EnvironmentObject var userSettings: UserSettings
    @ObservedObject var viewModel = TestViewModel()

    var body: some View {
        Text(viewModel.state)
            .onReceive(userSettings.$setting) { setting in
                self.viewModel.state = setting
            }
    }
}

UserSettings.setting 在另一个视图中更改时,它会导致我视图上的onReceive 在无限循环中被调用,我不明白为什么。我看到了this question,这个循环对我来说很有意义,因为观察到的ObservableObject 的状态会随着观察而改变。

但是,在我的情况下,我没有更改观察到的对象(环境对象)状态。我正在观察环境对象并更改重绘视图的视图模型状态。

视图是否重绘了导致问题的原因?每次重绘视图时都会调用onReceive 吗?

有没有更好的方法来完成我想做的事情?

编辑:这是我的问题的一个大大简化的版本。在我的应用程序中,视图模型负责根据用户的设置执行网络请求并更新视图的状态,例如显示错误消息或加载指示器。

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    从所描述的场景中,我看不到在视图模型中重复设置的原因。可以直接从userSettings显示值,如

    struct HomeView: View {
        @EnvironmentObject var userSettings: UserSettings
        @ObservedObject var viewModel = TestViewModel()
    
        var body: some View {
            Text(userSettings.setting)
        }
    }
    

    【讨论】:

    • 感谢您抽出宝贵时间回答,但正如我在对问题的编辑中解释的那样,我确实需要设置 viewModel。在我的应用程序中,我需要调用视图模型中的一个函数来执行网络请求,并且视图模型会在请求执行时设置视图的状态(例如显示错误消息、加载指示器等)
    • 你能想到为什么会发生循环行为吗?这对我来说是真正令人头疼的事情。
    • @gnarlybracket,关于简化问题的简化答案,因为我没有看到你需要自己推断的真实代码 - 逻辑中的循环,而不是 swiftui - 解决方案,如图所示,打破它。
    【解决方案2】:

    每当您有一个带有 @ObservedObject 的 onReceive 设置另一个(或相同)@ObservedObject 的已发布值时,如果这些已发布的属性以某种方式显示,您就有创建无限循环的风险。

    让你的 onReceive 验证接收到的值实际上是在更新一个值,而不仅仅是设置相同的值,否则它将无限设置/重绘。在这种情况下,例如:

    .onReceive(userSettings.$setting) { setting in
              if setting != self.viewModel.state {
                self.viewModel.state = setting
              }
          }
    

    【讨论】:

    • 谢谢!!!这实际上是唯一让我的代码正常工作的事情。你是个传奇!!
    【解决方案3】:

    您可以通过将@ObservedObject 切换为@StateObject 来防止无限地重新渲染视图主体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-27
      • 2021-05-07
      • 2012-08-24
      • 2020-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多