Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

SwiftUI iOS16 Table with optional string as keypath

How does one create a TableColumn for an optional property? Do i have to unwrap it in my model to make it an empty string if it is nil?

extension SomeObject {
    var someOptionalStringUnwrapped: String { return someOptionalString ?? "" }
}
Table(someObject) {
    TableColumn("Given Name", value: \.someString)
    TableColumn("Given Name", value: \.someOptionalString) // <--shows error mentioned below
    TableColumn("Given Name", value: \.someOptionalStringUnwrapped) // <--compiles
}

Key path value type ‘String?’ cannot be converted to contextual type ‘String’

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

As you said, unwrapping the optional in the model is one way you can solve this. Another solution would be to declare an extension on optionals, so you don’t have to do this for every property like this.

// this could also be "where Wrapped: StringProtocol"
extension Optional where Wrapped == String {
    var unwrapOrEmpty: Wrapped {
        self ?? ""
    }
}
TableColumn("Given Name", value: \.someOptionalString.unwrapOrEmpty)

Alternatively, create an extension on all RangeReplaceableCollections, which String conforms to.

extension Optional where Wrapped: RangeReplaceableCollection {
    var unwrapOrEmpty: Wrapped {
        self ?? .init() // init() makes an empty collection
    }
}

A third way is to use another overload of TableColumn, like this one which allows you to specify your own Content view.

init(_ titleKey: LocalizedStringKey, @ViewBuilder content: @escaping (RowValue) -> Content)

You can write an extension on TableColumn which delegates to the above initialiser:

extension TableColumn where RowValue: Identifiable, Sort == Never, Content == Text, Label == Text {
    init(
        _ titleKey: LocalizedStringKey,
        value: KeyPath<RowValue, String?>
    ) {
        self.init(titleKey) { rowValue in
            Text(rowValue[keyPath: value] ?? "")
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading