SwiftUI - if let 条件关闭的替代方法

SwiftUI - alternative to if let with a conditional closure

我正在尝试在 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 会导致以下错误:

Closure containing control flow statement cannot be used with function builder '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<(C0, C1)>' requires that '()' conform to 'View'

Type '()' does not conform to protocol 'View'

关于如何克服第二组错误的任何建议?或者,是否有另一种方法可以在 SwiftUI 中展开可选值并对其进行评估?真的很喜欢 SwiftUI,但不敢相信解包可选值是一件令人头疼的事情!

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")
}

重构(也适用于较早的 Swifts)

您可以将代码重构为更基本的代码,例如使用函数:

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 的未来版本将像我们期望的那样直接支持它。

对于这种情况,我更喜欢以下方法

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!")
        }
    }
}

您正在尝试对年龄的值进行两次检查:首先确保它不是 nil,然后检查它是否大于 0。 您可以使用 map 摆脱潜在的 nil 然后使用三元运算符有条件地更改显示的文本:

var body: some View {
    VStack {
        Text("Just a test")
        age.map { Text( [=10=] > 0 ? "Display Age: \([=10=])" : "Age must be greater than 0!") }
    }
}