当Publisher参数没有任何新值要发出时,为什么在SwiftUI视图上调用onReceive块?

acruukt9  于 2022-11-21  发布在  Swift
关注(0)|答案(1)|浏览(149)

我在SwiftUI中为一个视图附加了一个onReceive修饰符。订阅的目的是响应@Published属性greeting中的更改,该属性是视图Model对象的一部分。
视图包含一个分段选取器。分段选取器使用视图模型中的另一个属性--index
令人费解的是,当用户更改分段选取器选择时,即使Publisher greeting没有更改,也会调用onReceive块。

import SwiftUI
import Combine

class Model: ObservableObject {
    @Published var selectedIndex = 0
    @Published var greeting = "initial"
    
}

struct ContentView: View {
    @ObservedObject var model: Model
    let pickerTitles = ["One", "Two", "Three"]
    
    var body: some View {
        VStack {
            return Picker("Options", selection: $model.selectedIndex) {
                ForEach(0 ..< pickerTitles.count) { index in
                    Text(self.pickerTitles[index])
                }
                
            }.pickerStyle(SegmentedPickerStyle())
        }
        .onReceive([model.greeting].publisher){str in
            print(str)
        }
   
    }
}

上面的代码是整个代码库。
回复:摘要我在.onReceive区块中指定了出版者。指定的属性--greeting--永远不会变更。当同一ObservedObject中的选取器变更另一个属性--index--时,会神秘地呼叫.onReceive区块。

czq61nw1

czq61nw11#

您可以在程式码中使用Publishers.Sequence,它会逐一发布序列中的元素。
对于您的代码,每次计算body时,都会重新计算[model.greeting].publisher并重新创建发布者,这意味着已发布的元素重置为第一个。
使用下列程式码,您可以发现每次计算body时,都会打印出x

struct ContentView: View {
    @ObservedObject var model: Model
    let pickerTitles = ["One", "Two", "Three"]

    var body: some View {
        VStack {
            return Picker("Options", selection: $model.selectedIndex) {
                ForEach(0 ..< pickerTitles.count) { index in
                    Text(self.pickerTitles[index])
                }

            }.pickerStyle(SegmentedPickerStyle())
        }
        .onReceive(["x"].publisher){str in
            print(str)
        }
    }
}

如果你只想在greeting上接收更改,你可以写这样的代码:

struct ContentView: View {
    @ObservedObject var model: Model
    let pickerTitles = ["One", "Two", "Three"]

    var body: some View {
        VStack {
            return Picker("Options", selection: $model.selectedIndex) {
                ForEach(0 ..< pickerTitles.count) { index in
                    Text(self.pickerTitles[index])
                }

            }.pickerStyle(SegmentedPickerStyle())
        }
        .onReceive(model.$greeting){str in
            print(str)
        }
    }
}

相关问题