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

Posted

技术标签:

【中文标题】在视图外触发时如何绑定 SwiftUI.Alert 的呈现?【英文标题】:How to bind presentation of SwiftUI.Alert when triggered outside of the View? 【发布时间】:2019-06-25 21:32:23 【问题描述】:

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

showingAlert(source)为例:

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

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

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

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

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

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

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

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

可以做得更好吗?

【问题讨论】:

真相的来源在哪里?尽管声明它由两个抽象管理,但需要有一个单一的来源。如果不是,那么您正在做的事情还有其他问题。 (范式转变?) 感谢您的评论@dfd。更具体的例子是将网络请求委托给objectBindingURLSessionPublisher(由objectBinding 管理)可以发送DataError,因此objectBinding 是错误消息的真实来源。我不确定将Alert呈现/隐藏状态保留在那里是否是一个好习惯 是的 - 这绝对是一个范式转换问题。在命令式世界中,我只需订阅 Publisher,传递错误消息,触发警报并收工 - 呈现/隐藏状态将由视图本身管理,我不需要以某种方式缓存错误消息。 【参考方案1】:

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

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

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

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

【讨论】:

以上是关于在视图外触发时如何绑定 SwiftUI.Alert 的呈现?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:如何在其附件视图更改时触发 tableViewCell 的约束/自动布局刷新?

Stickit:如何在每个模型后触发更改事件 -> 视图更改

更新 ViewModel 时如何防止 Kendo UI Grid 多次重新绑定

我可以以编程方式触发淘汰视图模型更新吗?

切换 swiftUI toggle() 时如何触发操作?

在对话框外发生单击时如何触发事件