How to declare a TableColumn with nullable field?

How does one declare a TableColumn with a nullable field?

I have a Book model with several nullable fields:

struct Book: Codable, Equatable, Identifiable {
    // ...
    let productURL: String?
    // ...
}

This is how I'm trying define the corresponding TableColumn:

TableColumn("Product URL", value: \.productURL) { book in
    Text(String(book.productURL ?? ""))
}

Though this results in several errors:

  1. Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires that 'Book' inherit from 'NSObject'
  2. Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires that 'Book' inherit from 'NSObject'
  3. Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires the types 'KeyPathComparator' and 'SortDescriptor' be equivalent
  4. Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires the types 'KeyPathComparator' and 'SortDescriptor' be equivalent

Other, non-nullable columns work just fine. For example:

TableColumn("ID", value: \.id) { book in
    Text(String(book.id))
}
TableColumn("Slug", value: \.slug)
TableColumn("Category", value: \.category)
TableColumn("Title", value: \.title)
// ...
  • Did you just try to initialise it ? let productURL: String? = nil Note that I didn't test.

  • I already had an init constructor for the model. I tried initializing it where it's declared in the model, var productURL: String? = nil, however, that didn't make a difference.

  • One workaround would be to change my model to not have nullable fields, and set to "" when decoding a null. However, that to me, is a kludge. My model data is coming from a database table in Postgres where the column(s) are NULLABLE.

Replies

Try removing the value from TableColumn.

TableColumn("Product URL") { book in
    Text(String(book.productURL ?? ""))
}
  • I have the same issue trying to include a TableColumn for a property of type Date? and @nbenzie1's suggestion of simply not including the value argument in TableColumn solved it for me. I use an if let conditional to pass either a DatePicker or Text view to the TableColumn's content closure and it displays correctly.

    But it creates a different problem. It seems like it's not possible to sort by a TableColumn that does not include a KeyPath passed to the TableColumn's value argument. If I pass my optional date KeyPath/property to the TableColumn's value, it won't build, but if I omit it it won't sort.

    Is there a way to get a SwiftUI Table to be able to sort by a column of optionals?

Add a Comment

Is there a way to get a SwiftUI Table to be able to sort by a column of optionals?

You can extend Optional for your specific case. For example, if you are trying to sort by an optional Int:

extension Optional where Wrapped == Int {
  var sortOrder: Int {
    switch self {
    case let .some(wrapped): wrapped
    case .none: Int.max
    }
  }
}

Then your TableColumn would look like this:

TableColumn("Count", value: \.count.sortOrder) {
  if let count = $0.count {
    Text(String(count))
  }
}

If count is nil, it will be sorted as if its value is Int.max and the column will be blank for that row.