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.

Could you post complete code, so that we can try ?

Try removing the value from TableColumn.

TableColumn("Product URL") { book in
    Text(String(book.productURL ?? ""))
}

Your decoding process will need a way to represent nil values probably in the form of "" values so the table column can bind to the table row while reading from the items provider if you're reading from one.

Just ran into this issue too when working through a simple struct with Strings. A table of mostly strings with some columns sensibly optional Strings.

The compiler message displayed in Xcode 13.3 is:

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

So not helpful.

Removing the path does seem to work, but the docs would suggest that the column will no longer participate in sorting state of the table. I too can think of use cases where I have optional data but want the rest of the non-optional Strings to be sorted (either at the bottom or the top).

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.

How to declare a TableColumn with nullable field?
 
 
Q