3
votes

Anyone know if SwiftUI support ternary conditionals? I have a text view with conditional argument (Text(badgeCount == nil ? " " :"\(badgeCount!)")) that displays an empty view. Surprisingly, it works if I remove the @State attribute from the view.

import SwiftUI

struct RedBadgeView: View {
    @State var badgeCount: Int?
    
    init (_ badgeCount: Int? = nil) {
        self.badgeCount = badgeCount
    }
    
    var body: some View {
        // Something about this Syntax is throwing off SwiftUI. 
        Text(badgeCount == nil ? " " :"\(badgeCount!)")
    }
}

struct RedBadgeView_Previews: PreviewProvider {
    static var previews: some View {
        RedBadgeView(1)
    }
}

3

3 Answers

4
votes

There's no need to use the ternary operator here at all. Moreover, doing a nil check and then force unwrapping in a ternary operator is a bad idea.

Instead, you should use optional chaining to access the description of badgeCount and provide the " " as a default value.

Text(badgeCount?.description ?? " ")

However, your problem of the view not updating is coming from the fact that you never initialise your State, you just assign a value to its wrapped value. To access the state, you need to use the _ prefix before the variable name.

init (_ badgeCount: Int? = nil) {
    self._badgeCount = State(initialValue: badgeCount)
}
3
votes

Sure ternary conditions work. However you initialization of the State is wrong. You are initializing a regular Int.

init (_ badgeCount: Int? = nil) {
    self.badgeCount = badgeCount // >> If you initializing an Int
    self._badgeCount = State(initialValue: badgeCount) // >> If you initializing a State variable
}

Hence, everything will work with State aswell:

struct ContentView: View {
    @State var badgeCount: Int?
    
    init (_ badgeCount: Int? = nil) {
        self._badgeCount = State(initialValue: badgeCount)
    }
    
    var body: some View {
        Text(badgeCount == nil ? " " :"\(badgeCount!)")
    }
}
1
votes

In addition to other answers, if you're using SwiftUI 2 you can do it in more swifty way which is to use if-let directly in the body:

var body: some View {
    if let badgeCount = badgeCount {
        Text(badgeCount)
    }
}

If badgeCount is nil, the body will return an EmptyView. However, you may return some other view as well:

@ViewBuilder
var body: some View {
    if let badgeCount = badgeCount {
        Text(badgeCount)
    } else {
        Text(" ")
    }
}

(First you need to init/assign a value to badgeCount to see the view).