Swiftui Combine是否有仅在值实际更改时发布的发布服务器?

Swiftui Combine是否有仅在值实际更改时发布的发布服务器?,swiftui,combine,Swiftui,Combine,有没有办法使@Published变量仅在新值与旧值不同时才发布其值 现在如果我们有 @发布的var测试:Bool=false 我们确实如此 test = false test = false test = false 出版商被叫了三次。这很烦人,因为它有时会导致重新创建我的SwiftUI视图,因为在层次结构的更高位置,通过另一个触发的发布服务器将发布服务器设置为它以前设置的值(这会破坏文本字段输入,因为在这种情况下会重新创建通过层次结构的视图模型) 只有当它从false变为true或反之亦然时

有没有办法使
@Published
变量仅在新值与旧值不同时才发布其值

现在如果我们有

@发布的var测试:Bool=false

我们确实如此

test = false
test = false
test = false
出版商被叫了三次。这很烦人,因为它有时会导致重新创建我的SwiftUI视图,因为在层次结构的更高位置,通过另一个触发的发布服务器将发布服务器设置为它以前设置的值(这会破坏文本字段输入,因为在这种情况下会重新创建通过层次结构的视图模型)

只有当它从
false
变为
true
或反之亦然时,才有发布的方法吗

一个示例场景:

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


    @ObservedObject var viewModel = UserViewModel()


    var body: some View {
            if !viewModel.hasVehicles {
                return AnyView(AddVehicleView(viewModel:AddVehicleViewModel())
            } else {
                return AnyView(UserMainView(user: user))
            }
        }
    }
在我们的
UserViewModel

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

  • 某些代码在某些侦听器触发时更新该布尔值
AddVehicleView
中,我们有一个表单,允许用户填写一些文本字段并保存车辆

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

hasVehicles=false

并且顶层视图被重新计算,结果是执行
返回AnyView(AddVehicleView(viewModel:AddVehicleViewModel())
,带有文本字段的我的表单被清空


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

尝试使用常规属性和手动发布者激活就好像

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

这似乎是一个可行的解决方案,但我无法想象我是唯一一个在构建界面的快捷方式中遇到此类问题的人,一旦你有了管理屏幕的多层视图?我想知道我是否遗漏了什么。如果控制视图的状态没有改变值I,那么就不应该重新生成视图MO.@swiftPunk,这不是关于任意的副作用代码,而是关于ObservieObject概念用法的正确性,如所述,发布者应该是
objectWillChange
,即在对象更改之前。您不必担心
@Published
发布副本,它会触发“视图”重新评估,但不必重新绘制n-这就是扩散魔法发生的地方。不幸的是,你正在使用
AnyView
抛出所有扩散。最好的解决方案是不要使用
AnyView
,让
SwiftUI
完成它的工作。所以你要说的是,一旦你开始使用AnyView,你就会得到一个重画,因为SwiftUI认为它是一个新的v视图?如果是这种情况,您如何在视图中执行开关/If-else,返回两种不同的视图类型,而不使用AnyView?您是否支持iOS 13?如果将整个开关包装在
组中
,您应该能够删除
AnyView