How to implement a List of TextFields in SwiftUI without breaking deletion

Some ideas on this:

Option 1 (Inline Binding)

(I'm guessing that there might be a cleaner implementation, but this code works fine)

// Somewhere in MasterView...
// A function that returns a binding for the title of an event
func titleBindingFor(_ event: Event) -> Binding<String> {
    Binding<String>(get: { () -> String in
        event.title ?? ""
    }) { (title) in
        event.title = title
    }
}

then

// Bind it to the textfield
TextField("Title", text: self.titleBindingFor(event))

Option 2 (Separate View)

extension Optional where Wrapped == String {
    var safe: String {
        get { self ?? "" }
        set { self = newValue }
    }
}

struct TitleEditor: View {
    @ObservedObject var event: Event

    var body: some View {
        TextField("Title", text: $event.title.safe)
    }
}

then

TitleEditor(event: event)

Note: I also had to handle the optional timestamp force unwrap (really Apple?!) in DetailView cause I was getting crashes on deletion:

struct DetailView: View {
    @ObservedObject var event: Event

    var body: some View {
        let timestamp = event.timestamp ?? Date()
        return Text("\(timestamp, formatter: dateFormatter)")
            .navigationBarTitle(Text("Detail"))
    }
}

Notice that I'm returning an empty string if the title is nil, which is handled gracefully by the textfield (it shows the placeholder on newly created items)


Instead of

TextField("Title", text: Binding(ObservedObject(wrappedValue: event).projectedValue.title)!)

Use

TextField("Title", text: Binding<String>(
                   get: {event.title ?? "<none>"}, set: {event.title = $0}))

Tested & Works with Xcode 11.2, iOS 13.2