onReceive String.publisher导致无限循环 [英] onReceive String.publisher lead to infinite loop

查看:82
本文介绍了onReceive String.publisher导致无限循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在View中使用两个发布者:

I use two publishers in View:

A:String.publisher

A: String.publisher

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

B: ObservableObject include one @Published String type

如果我监视发布者A,则会遇到无限循环.但是监视发布者B是可以的!

If I monitoring publisher A,I get a infinite loop. But monitoring publisher B is OK!

    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导致了无限循环.这是为什么???谢谢:)

Although I changed model.someBool value in onReceive(),But Plan B is fine, Plan A lead to infinite loop. Why is That??? Thanks :)

推荐答案

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

Hopy, you need one source of true. If you don't like to use your model, the equivalent code with State / Binding pair could looks like

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
            }
        }
    }
}

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

In your example I disable (see the commented line) the default "request" in model

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 = ""
    @StateObject 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
...

现在取消注释模型中的线

Now uncomment the line in your model

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")
        }
    }
}

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

and run it again ... it will print in infinite loop

...
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 
...

您的模型发生了变化,SwiftUI正在重新评估其主体,由于这个原因,模型再次发生了变化……在循环中.

your model changes, SwiftUI is reevaluating its body and due this the model changes again ... in a loop.

最小循环示例

import SwiftUI
import Combine

class Model: ObservableObject {
    @Published var flag = false
}
struct ContentView: View {
    @StateObject var model = Model()
    var body: some View {
            Color.yellow
                .onReceive(model.$flag) {_ in
                    print(".")
                self.model.flag.toggle()
            }
    }
}

这篇关于onReceive String.publisher导致无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆