在视图之外触发时如何绑定 SwiftUI.Alert 的呈现?

Mac*_*nik 5 ios swift ios13 swiftui combine

显示的大多数示例是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!"))
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Button(action: {
    self.showingAlert = true
}
Run Code Online (Sandbox Code Playgroud)

但是如果我们想用特定的消息从控制器/视图模型层触发它呢?作为一个例子,我们做一个网络电话-的URLSessionPublisher可以发送DataError我们要推给用户的消息Alert

@State旨在从视图的 进行管理body,因此@ObjectBinding在这种情况下,我们似乎更应该使用 an 。看来我们还需要一些message,所以我们可以在body

Alert(
    title: Text("Important message"),
    message: Text(objectBinding.message)
)
Run Code Online (Sandbox Code Playgroud)

showingAlert会是一个有点多余这里我们可以定义messageString?,创造一个结合presentation

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

Run Code Online (Sandbox Code Playgroud)

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

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

可以做得更好吗?

hec*_*ckj 1

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

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

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

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