5

大多数显示示例是Alert指某种@State被用作控制警报视图的呈现/隐藏状态的绑定。

例如showingAlert来源):

struct ContentView : View {
    @State var showingAlert = false
    
    var body: some View {
        Button(action: {
            self.showingAlert = true
        }) {
            Text("Show Alert")
        }
        .alert(isPresented: $showingAlert) {
            Alert(
                title: Text("Important message"),
                message: Text("Wear sunscreen"),
                dismissButton: .default(Text("Got it!"))
            )
        }
    }
}

当从 UI 层触发警报时,这是一个很好的解决方案 - 如示例所示:

Button(action: {
    self.showingAlert = true
}

但是如果我们想用特定的消息从控制器/视图模型层触发它呢?例如,我们进行网络调用 -URLSession可以Publisher发送DataError我们想要作为消息推送给用户的Alert.

@State被设计为从视图中管理body,所以在这种情况下我们似乎应该使用 an @ObjectBinding。看来我们也需要一些message,所以可以在下面引用body

Alert(
    title: Text("Important message"),
    message: Text(objectBinding.message)
)

在这里showingAlert会有点多余,因为我们可以定义messageString?并创建一个绑定presentation

Binding<Bool>(
    getValue: { objectBinding.message != nil },
    setValue: { if !$0 { objectBinding.message = nil } }
)

这是一种可行的方法并且有效,但有两件事让我有点焦虑:

  1. message由两个抽象管理的事实
  2. 警报的显示/隐藏状态的信息和管理泄漏到控制器/视图模型/对象绑定中。最好将呈现/隐藏状态私下保留在视图中。
  3. 事实上,消息一直保存在控制器/视图模型/对象绑定中,直到它被视图(绑定)“消耗”。

可以做得更好吗?

4

1 回答 1

0

如果您特别想使用 Combine 及其发布者机制,您可以使用onReceive(). 每个通用 SwiftUI 视图都有onReceive()一个通用函数,它接受发布者,并在实例化时订阅发布者。sink如果您熟悉的话,它的行为与 Combine 订阅者的单闭包版本非常相似。

发布者的细节期望发布者失败类型为 Never 才能正常工作,因此如果您在某个管道中使用错误,则需要将它们转换为其他类型的对象(可能Enum具有关联String值)和将它们外部化,以便它们可以使用 SwiftUI 显示。

你最终如何将发布者暴露给 SwiftUI 视图可能也很尴尬——我一直在通过将发布者添加到具有其他@Published属性的引用对象上来做到这一点。

您可以在https://heckj.github.io/swiftui-notes/#pattern-observableobject的Using Combine中查看其工作原理的粗略示例(尽管不是您的特定用例)

于 2020-02-26T17:36:38.647 回答