SwiftUI:为什么 onReceive 在 ObservableObject 内绑定字段时运行重复?

发布于 2025-01-10 17:59:50 字数 671 浏览 1 评论 0原文

这是我的代码,当文本更改(如图像)时,“print(”run to onReceive (text)”)”运行两次。为什么?谢谢你!

import SwiftUI

class ContentViewViewModel : ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()
    
    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }
        .onReceive(viewModel.$text) { text in
            print("run to onReceive \(text)")
        }
    }
}

输入图片此处描述

This is my code and "print("run to onReceive (text)")" run twice when text change (like a image). Why? and thank you!

import SwiftUI

class ContentViewViewModel : ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()
    
    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }
        .onReceive(viewModel.$text) { text in
            print("run to onReceive \(text)")
        }
    }
}

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妄断弥空 2025-01-17 17:59:50

我认为这是因为视图会随着 ViewModel 中的 @Published 属性的更改而自动更新,并且 .onReceive 修饰符会由于创建的 2 路绑定而再次更新视图viewModel.$text 导致视图每次更新两次。

如果您想在文本更改时打印文本,可以使用 .onChange 修饰符。

class ContentViewViewModel: ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()

    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }.onChange(of: viewModel.text) { newValue in
            print("run to onChange \(newValue)")
        }
    }
}

SwiftUI 中的 onChanged

I think it's because the view is automatically updated as your @Published property in your ViewModel changes and the .onReceive modifier updates the view yet again due to the 2 way binding created by viewModel.$text resulting in the view being updated twice each time.

If you want to print the text as it changes you can use the .onChange modifier instead.

class ContentViewViewModel: ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()

    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }.onChange(of: viewModel.text) { newValue in
            print("run to onChange \(newValue)")
        }
    }
}

onChanged in SwiftUI

辞别 2025-01-17 17:59:50

因为视图的 @StateObject 中有一个 @Published 变量,所以该变量中的更改将自动更新视图。

如果添加 .onReceive() 方法,您将:

  • 更新视图,因为您有 @Published var
  • .onReceive()< /code> 方法监听变化

只需完全删除 .onReceive() 即可工作:

class ContentViewViewModel : ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()
    
    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }

        // It still works without this modifier
        //.onReceive(viewModel.$text) { text in
        //    print("run to onReceive \(text)")
        //}
    }
}

Because you have a @Published variable inside the @StateObject of your view, the changes in that variable will automatically update the view.

If you add the .onReceive() method, you will:

  • update the view because you have the @Published var
  • update it again when the .onReceive() method listens to the change

Just delete the .onReceive() completely and it will work:

class ContentViewViewModel : ObservableObject {
    @Published var text = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewViewModel()
    
    var body: some View {
        ZStack {
            TextField("pla", text: $viewModel.text)
                .padding()
        }

        // It still works without this modifier
        //.onReceive(viewModel.$text) { text in
        //    print("run to onReceive \(text)")
        //}
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文