联合收割机是否有仅在值实际发生变化时发布的发布者?

Jor*_*ans 5 swiftui combine

有没有一种方法可以使@Published变量仅在新值与旧值不同时才发布其值?

现在如果我们有

@Published var test: Bool = false

我们做

test = false
test = false
test = false
Run Code Online (Sandbox Code Playgroud)

发布者被呼叫 3 次。这是非常烦人的,因为它有时会导致我的 SwiftUI 视图被重新创建,因为在层次结构中较高的某个位置,发布者被设置为之前设置的值,通过另一个被触发的发布者(并且会破坏文本字段输入,因为视图模型通过当发生这种情况时,层次结构将被重新创建)。

有没有一种方法只在从 到falsetrue从 到 时才发布?

一个示例场景:

我们在应用程序中创建一个用户对象,并且想要向该用户添加一辆车。如果没有找到汽车,应用程序应立即显示“添加汽车”视图,否则显示主应用程序视图。为此,我们在某处有一个监听器。在我们的顶层视图中,我们有:


    @ObservedObject var viewModel = UserViewModel()


    var body: some View {
            if !viewModel.hasVehicles {
                return AnyView(AddVehicleView(viewModel:AddVehicleViewModel())
            } else {
                return AnyView(UserMainView(user: user))
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

在我们的UserViewModel我们有

class UserViewModel: ObservableObject {
    @Published var hasVehicles: Bool = false

Run Code Online (Sandbox Code Playgroud)
  • 当某些侦听器触发时更新该布尔值的一些代码。

在里面AddVehicleView我们有一个表单,允许用户填写一些文本字段并保存车辆。

现在想象一下,由于某种原因,更新属性的代码hasVehicles被触发,但仍然没有车辆。会发生什么:

hasVehicles = false

并且顶级视图被重新评估,导致return AnyView(AddVehicleView(viewModel:AddVehicleViewModel())被执行,并且我的带有文本字段的表单被清空。

我想在这种情况下,我可以通过将其AddVehicleViewModel()作为属性放入View结构中来解决它,但是当我们希望多次执行它时,这并不能解决它,因为这意味着下次构建视图时它将显示我们上次创建该视图时的数据,因为我们重用了视图模型。

小智 8

removeDuplicates()在更新属性的代码中使用合并运算符。例如,视图模型可以创建一个发布者,该发布者根据其他两个布尔属性的值更新布尔属性:

    @Published var hasTrucks: Bool
    @Published var hasCars: Bool
    @Published var hasVehicles: Bool

    func createVehiclePublisher() {
        Publishers.CombineLatest($hasTrucks, $hasCars)
            .map { $0 || $1 }
            .removeDuplicates()
            .assign(to: &$hasVehicles)
    }
Run Code Online (Sandbox Code Playgroud)

使用removeDuplicates()原因hasVehicles仅当其值发生变化时才更新。


Asp*_*eri 2

尝试使用常规属性并手动激活发布者,例如

class UserViewModel: ObservableObject {
    var hasVehicles: Bool = false {
        willSet {
            if hasVehicles != newValue {
                objectWillChange.send()
            }
        }
    }
// ... other code
}
Run Code Online (Sandbox Code Playgroud)