onReceive String.publisher导致无限循环

问题描述 投票:0回答:1

我在视图中使用两个发布者:

A:String.publisher

B:ObservableObject包含一种@Published字符串类型

如果我监视发布者A,则会出现无限循环。但是监视发布者B是可以的!

    import SwiftUI
    import Combine

    class Model: ObservableObject{
        @Published var someBool = false
        @Published var name:String = ""
    }

    struct ContentView: View {
        // Publisher A
        @State var name = ""
        // Publisher B
        @ObservedObject var model = Model()

        var body: some View {
            VStack {
                // Plan A: lead to infinite loop!!!
                TextField("Input Name", text: $name)
                // Plan B: It's OK
                //TextField("Input Name", text: $model.name)

                .onReceive(name.publisher.reduce("", {t,c in
                    t + String(c)
                })) {text in
                    print("change to \(text)")
                    self.model.someBool.toggle()    //Plan A: infinite loop!!!
                }
                /*
                .onReceive(model.$name){name in
                    print("change to \(name)")
                    self.model.someBool.toggle()    //Plan B: It's OK!!!
                }
                */
            }
        }
    }

尽管我在onReceive()中更改了model.someBool值,但是计划B很好,计划A导致了无限循环。这是为什么???谢谢:)

swift swiftui combine
1个回答
0
投票

希望,您需要一个真实的来源。如果您不喜欢使用模型,则具有状态/绑定对的等效代码可能看起来像

struct ContentView: View {
    @State var name: String = ""
    @State var flag = false
    var body: some View {
        let subject = CurrentValueSubject<String, Never>(name)
        return VStack {
            TextField("Input Name", text: $name).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
            .onReceive(subject) { name in
                print("change to \(name)")
                self.flag.toggle() // toggle every char typing
            }
        }
    }
}

在您的示例中,我禁用(请参见注释行)模型中的默认“请求”

import SwiftUI
import Combine

class Model: ObservableObject{
    var someBool = false {
        willSet {
            print("will change to", newValue)
            print("ask SwiftUI to update from model")
            //self.objectWillChange.send()
        }
        didSet {
            print(oldValue, "changed")
        }
    }
}

struct ContentView: View {
    @State var name = ""
    @ObservedObject var model = Model()

    var body: some View {
        VStack {
            TextField("Input Name", text: $name).textFieldStyle(RoundedBorderTextFieldStyle())

            .onReceive(name.publisher.reduce("", {t,c in
                t + String(c)
            })) {text in
                print("change to \(text)")
                self.model.someBool.toggle()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

打印时输入

true changed
change to Qw
will change to true
ask SwiftUI to update from model
false changed
change to Qwe
will change to false
ask SwiftUI to update from model
true changed
change to Qwer
will change to true
ask SwiftUI to update from model
false changed
change to Qwert
will change to false
ask SwiftUI to update from model
true changed
...

现在取消注释模型中的线

class Model: ObservableObject{
    var someBool = false {
        willSet {
            print("will change to", newValue)
            print("ask SwiftUI to update from model")
            self.objectWillChange.send()
        }
        didSet {
            print(oldValue, "changed")
        }
    }
}

然后再次运行...它将无限循环打印

...
change to 
will change to true
ask SwiftUI to update from model
false changed
change to 
will change to false
ask SwiftUI to update from model
true changed
change to 
will change to true
ask SwiftUI to update from model
false changed
change to 
will change to false
ask SwiftUI to update from model
true changed
change to 
...
© www.soinside.com 2019 - 2024. All rights reserved.