[SOLVED] IOS 16 Table sort by tableColumn where keyPath is a Bool

Issue

This Content is from Stack Overflow. Question asked by Stewart Lynch

I am working with the new Table struct in SwiftUI made available to iOS in iOS 16. I have a simple model

struct City: Identifiable {
   var name: String
   var country: String
   var population: Int
   var isCapital: Bool = false
   var id: String {
       name
   }

   static var sample: [City] {
       [
           City(name: "Vancouver", country: "Canada",  population:  2632000),
           ...
           ...
       ]
   }
}

And a simple View that displays the table and I am trying to sort by columns

struct CountryTableView: View {
   @State private var sampleCities = City.sample.sorted(using: KeyPathComparator(.name))
   @State private var sortOrder = [KeyPathComparator(City.name)]
   var body: some View {
       Table(sampleCities, sortOrder: $sortOrder) {
           TableColumn("Name", value: .name)
           TableColumn("Capital") { city in
               HStack {
                   Spacer()
                   Text(city.isCapital ? "🌟" : "")
                   Spacer()
               }
           }
           .width(60)
           TableColumn("Country", value: .country)
        
           TableColumn("Population", value: .population) { city in
               Text("(city.population)")
           }
       }
       .onChange(of: sortOrder) { newOrder in
           sampleCities.sort(using: newOrder)
       }
   }

}

The above works well. I can sort on both of the String and Int KeyPaths. However,if I try to add a value for the Boolean keypath

 TableColumn("Capital", value: .isCapital) { city in

I get this error

Referencing initializer 'init(_:value:content:)' on 'TableColumn' requires the types 'KeyPathComparator<City>' and 'SortDescriptor<City>' be equivalent

and this one

Referencing initializer 'init(_:value:content:)' on 'TableColumn' requires that 'City' inherit from 'NSObject'

This makes no sense to me as I can sort on String and Int KeyPaths but not the Boolean one.
Can anyone shed some light?



Solution

The docs (https://developer.apple.com/documentation/swiftui/tablecolumn/) do not mention using Bool for value in columns (lots of Int), but
you could try this approach, using a computed property, works for me:

struct City: Identifiable {
    var name: String
    var country: String
    var population: Int
    var isCapital: Bool = false
    var id: String {
        name
    }
    
    var isCapitalString: String { // <-- here
        isCapital ? "🌟" : ""
    }
    
    static var sample: [City] {
        [
            City(name: "Vancouver", country: "Canada", population: 2632000),
            City(name: "Tokyo", country: "Japan", population: 1632000, isCapital: true),
            City(name: "Sydney", country: "Australia", population: 32000)
        ]
    }
}

struct ContentView: View {
    
    @State private var sampleCities = City.sample.sorted(using: KeyPathComparator(\.name))
    @State private var sortOrder = [KeyPathComparator(\City.name)]
    
    var body: some View {
        Table(sampleCities, sortOrder: $sortOrder) {
            TableColumn("Name", value: \.name)
            
            TableColumn("Capital", value: \.isCapitalString) { city in // <-- here
                Text(city.isCapitalString)
            }.width(60)
            
            TableColumn("Country", value: \.country)
            
            TableColumn("Population", value: \.population) { city in
                Text("\(city.population)")
            }
        }
        .onChange(of: sortOrder) { newOrder in
            sampleCities.sort(using: newOrder)
        }
    }
}


This Question was asked in StackOverflow by Stewart Lynch and Answered by workingdog support Ukraine It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?