How can we have "one source of truth" when SwiftUI doesn't support optionals?

145 Views Asked by At

I need to display and allow the editing of a class whose members are mostly optional. This does not appear to be a scenario that SwiftUI envisions, despite Apple propagating the "single source of truth" mantra in its SwiftUI tutorials. What is the expected approach?

Take this class, for example, which represents a user:

class User : Equatable, Codable, ObservableObject
{
    var ID: String
    var username:  String
    var firstName: String?
    var lastName: String?
    var EMail: String?
    var phoneNbr: String?
    var avatarURL: String?
    var mediaServiceID: String?
    var validated: Bool = false
...
}

I can't directly show a form to fill this thing out in SwiftUI, because you can't bind text fields to optionals. Most of the published workarounds to that involve using let to create a non-optional variable if the member isn't nil; but this is unworkable because that won't populate a nil member if someone enters text in the text field. Apple docs talk about custom binding, which would probably work to populate an optional member. That means doing this in the SwiftUI view to set the object's username, for example:

@State private var      tempUser = User()

private var username: Binding<String>
{
    Binding { tempUser.username ?? "" }
    set: { newName in
        tempUser.username = newName
    }
}

But that means setting up one of these verbose methods for every single optional member of every class I want to show in a UI. At that point I might as well just make a shadow structure that's all non-optionals that I can bind directly to. Or just make all the members non-optional and just face the fact that optionals are done with in the age of SwiftUI.

Or is there some succinct approach I'm missing here? Thanks for any insight.

1

There are 1 best solutions below

6
Rob Napier On

I need to display and allow the editing of a class whose members are mostly optional.

That has always been a bad design, not just SwiftUI. In what way is nil different from empty? From your binding, you're indicating they're the same. If that's the case, then it should never have been Optional in the first place. It should just have been a normal String and made empty.

You're correct that SwiftUI can make this kind of bad design even harder than it's been in the past, but it was always hard. Redesign your type to only use Optionals for things where nil has a distinct meaning.

Of particular interest is that ID is optional. How can this type work with no ID?

To the headline question of whether Optionals are over, that absolutely is not the case. Optionals are as much a critical part of Swift as they've ever been. But representing "empty" as two different values (an empty thing like "", and also nil) is not something SwiftUI (or Swift) encourages. It will tend to be a pain.

That said, macros and property wrappers can write the code for you if you need it. I recommend fixing your data before going down that path, however.