SwiftUI 基于计算属性显示警报
Posted
技术标签:
【中文标题】SwiftUI 基于计算属性显示警报【英文标题】:SwiftUI show alert based on computed property 【发布时间】:2020-02-23 00:09:23 【问题描述】:我正在尝试基于计算属性在 Swift 中显示警报。基本上,每当用户单击按钮时,“round”的值都会更新。当进行超过 10 轮时,会显示警报。
为此,我创建了一个名为“showingAlert”的布尔变量。这必须是一个 @State 变量,以便在用户关闭警报时再次设置为 false。
但是,编译器告诉我像@State 这样的属性包装“不能应用于计算属性”:-(
这是我尝试过的代码:
@State var round = 0
@State var showingAlert:Bool round > 10 ? true : false
func result(player: Int, app: Int)
if player > app
round += 1
else
round += 1
var body: some View
Button(action: self.result(player: 1, app: 1))
Text("Button")
.alert(isPresented: $showingAlert)
Alert(title: Text("title"), message: Text("message"), dismissButton: .default(Text("Continue"))
)
有没有办法解决这个问题?我很想创建一个不显示错误消息的警报。
【问题讨论】:
你不能在 if/else 之后直接添加round > 10 ?...
代码吗? showingAlert = round > 10 ? true : false
。顺便说一句,你的 if 和 else 正在做同样的事情
【参考方案1】:
我更喜欢将逻辑放入模型中 - 将逻辑与视图分离 - 但这里有一些可行的方法:
@State var round = 0
@State var showingAlert:Bool = false
func result(player: Int, app: Int)
if player > app
round += 1
else
round += 1
if round > 10
showingAlert.toggle()
基本上,将您的支票移入您的功能。备注:
我假设这是测试逻辑...如果不是,您的if/else
中有错字,因为它们都做同样的事情。
仅将 showingAlert
设置为 true - 让 SwiftUI 在解除警报时将其设置为 false。
将此逻辑与视图分开的真正原因是您可以使事情变得容易重置round
。这是执行此操作的代码:
import SwiftUI
import Combine
class Model : ObservableObject
var objectWillChange = PassthroughSubject<Void, Never>()
@Published var showingAlert = false
willSet
objectWillChange.send()
if newValue == false
round = 0
var round = 0
func result(player: Int, app: Int)
if player > app
round += 1
else
round += 1
if round > 10
showingAlert.toggle()
struct ContentView: View
@EnvironmentObject var model: Model
var body: some View
Button(action: self.model.result(player: 1, app: 1))
Text("Button")
.alert(isPresented: self.$model.showingAlert)
Alert(title: Text("title"), message: Text("message"), dismissButton: .default(Text("Continue")))
请注意,只有一个变量 (showingAlert
) 标记为 @Published
,您可以针对 willSet
正确编码,而您需要在 ContentView
中更改的所有内容是添加 EnvironmentObjectafter your add it to your
SceneDelegate`正确。
第一组代码将在第 11 次点击后显示警报,然后每次点击。第二组代码将在第 11 次点击后显示警报,之后每 11 次点击。
【讨论】:
为什么模型对象应该有一个属性来确定是否应该显示警报,这会在模型和控制器层之间创建不必要的依赖关系。如果你想为此使用模型对象,那么它应该发布round
属性。或者至少将其重命名为符合逻辑的名称,例如 gameIsOver
@JoakimDanielson,我想这是风格问题。 (不过我明白你的意思。)但不是警报,让我们让它成为一个全屏模式 - 并发生后台进程。也许模型需要知道视图发生了什么。我想问题是什么驱动 UI - 用户交互和模型?还是 UI 驱动模型?
我不认为模型应该驱动任何东西或知道控制器或视图层发生了什么,它应该只是保持一个状态。然后由控制器层来响应该状态的变化或查询模型对象,因为一些内部请求或来自视图的请求。请注意,我认为您的回答没有任何问题,这更像是一条评论。【参考方案2】:
您可以简单地使用Binding.constant(_:)。将计算属性转换为绑定属性。
@State var round = 0
var showingAlert:Bool round > 10 ? true : false
func result(player: Int, app: Int)
if player > app
round += 1
else
round += 1
var body: some View
Button(action: self.result(player: 1, app: 1))
Text("Button")
.alert(isPresented: .constant(showingAlert))
Alert(title: Text("title"), message: Text("message"), dismissButton: .default(Text("Continue"))
)
【讨论】:
如果我像.alert(isPresented: .constant(showingAlert))
这样使用,则无法解除警报
是和否,两者兼而有之。是的,因为您不能直接切换显示警报变量,因为它是计算属性,但如果您想切换,您可以简单地更改依赖状态变量,使其切换计算值,在这种情况下为 round
以上是关于SwiftUI 基于计算属性显示警报的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - @Binding 到访问 ObservableObject 属性内的值的计算属性会复制变量吗?