SwiftUI - if let 有条件闭包的替代方案
Posted
技术标签:
【中文标题】SwiftUI - if let 有条件闭包的替代方案【英文标题】:SwiftUI - alternative to if let with a conditional closure 【发布时间】:2019-12-28 06:49:05 【问题描述】:我正在尝试在 SwiftUI 中实现以下功能:
struct PersonView: View
@State private var age: Int? = 0
var body: some View
VStack
Text("Just a test")
if let self.age > 0
Text("Display Age: \(age)")
else
Text("Age must be greater than 0!")
但是,在 SwiftUI 中,if let
会导致以下错误:
包含控制流语句的闭包不能与函数生成器“ViewBuilder”一起使用
所以在研究了这个主题之后,我发现了一个建议,即使用 .map
来解开 age
可选。因此,我修改为VStack
中的代码如下:
Text("Just a test")
self.age.map elem in
if elem > 0
Text("Display Age: \(elem)")
else
Text("Age must be greater than 0!")
但是,在 .map
闭包中包含条件会导致调用 VStack
的行出现以下错误:
' (ViewBuilder.Type) -> (C0, C1) -> TupleView' 要求 '()' 符合 'View'
类型'()'不符合协议'View'
关于如何克服第二组错误有什么建议吗?或者,是否有另一种方法可以在 SwiftUI 中展开选项并评估它们?真的很喜欢 SwiftUI,但不敢相信解包选项令人头疼!
【问题讨论】:
【参考方案1】:对于这种情况,我更喜欢以下方法
struct PersonView: View
@State private var age: Int? = 0
var body: some View
VStack
Text("Just a test")
AgeText
private var AgeText: some View
if let age = self.age, age > 0
return Text("Display Age: \(age)")
else
return Text("Age must be greater than 0!")
【讨论】:
请注意,如果您想在if let
条件失败的情况下尝试提供EmptyView()
,则此方法不起作用。因此,@LuLuGaGa 建议使用 .map 可能更可取
我很好奇为什么初始版本不起作用以及这实际上是如何解决问题的?似乎 (jasonzurita.com/swiftui-if-statement) 涵盖了一些主题,但它相当复杂。【参考方案2】:
Swift 5.3 (Xcode 12)
现在您可以在视图构建器中使用条件绑定了:
if let age = age
if age > 0
Text("Display Age: \(age)")
else
Text("Age must be greater than 0!")
else
Text("Age not found")
重构(也适用于较旧的 Swift)
您可以将代码重构为更基本的东西,例如使用函数:
var body: some View
VStack
Text("Just a test")
Text(text(age: age)) // Using the function
func text(age: Int?) -> String // Defining the function
guard let age = age else return "Age not found"
if age > 0 return "Display Age: \(age)"
else return "Age must be greater than 0!"
一般来说,在需要清理代码的地方使用函数。我希望未来的 Swift 版本能够像我们期望的那样直接支持这一点。
【讨论】:
感谢 @Mojtaba 的重构。除了克服不支持if let
和guard let
的SwiftUI 缺点之外,绝对组织得更好。最后,我接受了 Asperi 的解决方案,因为它也重构了 View
对象。【参考方案3】:
您尝试对 age 的值进行两次检查:首先确保它不是 nil
,然后检查它是否大于 0。
您可以使用 map 去除潜在的nil
,然后使用三元运算符有条件地更改显示的文本:
var body: some View
VStack
Text("Just a test")
age.map Text( $0 > 0 ? "Display Age: \($0)" : "Age must be greater than 0!")
【讨论】:
谢谢@LuLuGaGa!使用三元运算符帮助我解决了这个问题。我最终接受了 Asperi 的解决方案,因为它是一种更通用的方法,可以更好地组织代码,并且可以克服 SwiftUI 的 noet 支持if let
的不足。以上是关于SwiftUI - if let 有条件闭包的替代方案的主要内容,如果未能解决你的问题,请参考以下文章