【问题标题】:Check multiple @Published values检查多个@Published 值
【发布时间】:2021-08-01 00:10:57
【问题描述】:

我有 3 个课程:

class ClassOne: ObservableObject {
    @Published var loading: Bool = false
}

class ClassTwo: ObservableObject {
    @Published var loading: Bool = false
}

class ClassThree: ObservableObject {
    @Published var loading: Bool = false
}

在 SwiftUI 视图中,当所有 loading 变量都是 true 时,我需要做一些事情

这当然是我的文件的简化版本:每个类的加载 var 通过下载方法设置为 true 或 false。 我只需要检查所有下载是否已完成并删除加载视图。

struct MainScreen3: View {
    @State private var cancellables = Set<AnyCancellable>()
    @EnvironmentObject var classOne: ClassOne
    @EnvironmentObject var classTwo: ClassTwo
    @EnvironmentObject var classThree: ClassThree
    
    @State private var loading: Bool = true
    
    var body: some View {
        VStack {
            if loading {
                Text("Please wait...")
            } else {
                Text("Done!")
            }
            
        }.onAppear {
            self.classOne.fetchFromServer()
            self.classTwo.fetchFromServer()
            self.classThree.fetchFromServer()
        }
    }
}

有什么建议吗?

【问题讨论】:

    标签: swift combine observableobject


    【解决方案1】:

    您可以使用计算属性。

    private var loading: Bool {
       (self.classOne.loading || self.classTwo.loading || self.classThree.loading)
    }
    

    【讨论】:

    • 确实是一个很好的答案,但我只在第一次加载视图时计算。我需要在类的 loading 更改时更新视图(下载完成后它会更改)
    • 由于从所有 API 来看,任何单个参数都在视图中使用,因此如果更新 var,它会自动更改。
    • “仅在第一次加载视图时计算”——不正确。 SwiftUI 知道您何时从 body 方法访问 EnvironmentObject 的属性,例如 classOne。它记得如果classOneobjectWillChange 发布者触发,它需要再次调用bodyclassTwoclassThree 相同。
    • 但是这个计算出的loading 属性的主体是错误的,因为当且仅当没有类正在加载时,它才会返回true。相反,它应该类似于private var loading: Bool { classOne.loading || classTwo.loading || classThree.loading }
    • @robmayoff 感谢您的解释:当您访问 anEnvironmentObject 的属性时,我错过了 SwiftUI 知道的点,例如来自body 的 classOne,所以对于我的问题,这是另一个有效的解决方案。
    【解决方案2】:

    您可以使用 combineLatest 将所有 3 个加载值组合成一个 Publisher。您可以在视图上使用 onReceive 订阅此发布者,并更新现有的 loading State 属性以触发 UI 更新。

    .onReceive(classOne.$loading.combineLatest(classTwo.$loading, classThree.$loading, { $0 && $1 && $2 })) { loading in
        self.loading = loading
    }
    

    【讨论】:

    • 是的,这就是我试图做的。我的示例比实际代码更简单。只有 3 个已发布值,这是正确的,但在我的真实场景中,我有 8 个“加载”类......如何将您的解决方案应用于这么多变量?
    • @KScamorza 你需要实现一个CombineLatestMany 发布者,类似于MergeManyHere's 一个可能的实现。
    • 完美运行!感谢您的建议@Dávid Pásztor
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 2012-12-04
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多