'SwiftUI conditionally rendering one view or another

struct ContentView: View {
    @EnvironmentObject var demoModel: DemoModel

    var body: some View {
        //this works
        demoModel.isLoggedIn ? Text("logged in"):Text("logged out")

        //this doesnt work why
        //demoModel.loggedIn ?  StationListView(): LoginView()
    }
}


Solution 1:[1]

When you initialize a View (let's say A) in the body of another View, what happens is that A is passed as an argument to some special functions generated by the compiler: this system of having implicit function calls in a context (in this case the body of this View) is called "function builders", and they can be customized to have different behaviors. The one used in SwiftUI is ViewBuilder: it "collects" all the Views that you make in the body and "merges" them in a single one (that's why the return type of body is some View).

ViewBuilder contains some tricks to handle language constructs like if statements by embedding logic like "show one view or the other" but, as of the current version of Swift (5.2), it doesn't support most other tools like 'if let, guard let, do catch'. Some of these will become available in the next Swift version.

One of the unsupported things is the ternary operator ?:. In your example, the first line works because you're returning the same value for both the true and the false branches, but in the second line you're returning Views of different types, resulting in an error. Note that the same logic, used in a ViewBuilder context (Group) works just fine:

Group {
    if demoModel.isLoggedIn {
        Text("Logged in")
    } else {
        LoginView()
    }
}

And that's because ViewBuilder knows how to manage simple if statements.

Solution 2:[2]

For opaque returns, as some View here, it should be returned one type, so use Group, as below

Group {
    if demoModel.loggedIn {
        StationListView()
    } else {
        LoginView()
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tiziano Coroneo
Solution 2 Asperi