HI. I'm trying to replace a hacky LazyVGrid view I cobbled together to display a table of player stats (name, games, scores, etc.) that are saved as a Core Data entity, with the new (to iOS 16) Table view.
Benefits of this are: 1. less hacky (hopefully), 2. resortable by different categories (games, points, etc.)
I manage to have a table appear, but I can't do the reordering. When I put the .onChange(of: sortOrder) {...} I get one of the cryptic "The compiler is unable to type-check this expression in reasonable time..." at the var body: some View stage.
If I instead use a sample array (so not coming from Core Data), it works fine. The array I create to test the sortable table is an Identifiable one (which it needs to be to re-sort).
I think the issue is the Identifiable part. I just added a UUID to the Core Data entity, which didn't do anything. I don't know how to declare the fetch request to be Identifiable, or if that even makes sense.
Here is what does NOT work:
struct StatsView: View {
@FetchRequest(sortDescriptors: []) var stats: FetchedResults<PlayerStats>
@State private var sortOrder = [KeyPathComparator(\PlayerStats.name)]
var body: some View {
if #available(iOS 16.0, *) {
Table(stats, sortOrder: $sortOrder) {
TableColumn("Player", value: \.name!)
TableColumn("W-L", value: \.wins) {stats in Text("\(stats.wins)" + " - " + "\(stats.losses)")}
TableColumn("Points", value: \.points) {stats in Text("\(stats.points)")}
TableColumn("Innings", value: \.innings) {stats in Text("\(stats.innings)")}
TableColumn("LR", value: \.longRun) {stats in Text("\(stats.longRun)")}
TableColumn("Avg", value: \.lastAvg) {stats in Text("\((stats.lastAvg), specifier: "%.3f")")}
}
.onChange(of: sortOrder) { newOrder in
stats.sort(using: newOrder)}
}
else {...} \\old hacky lazyVGrid based table
}
}
Again: if I comment out the .onChange modifier, it compiles and the table shows.
Here is what DOES work:
struct PlayerStat: Identifiable {
let id: Int
var name: String
var wins: Int
var losses: Int
var points: Int
var innings: Int
var longRun: Int
var lastAvg: Double
}
struct ContentView: View {
@State private var sortOrder = [KeyPathComparator(\PlayerStat.name)]
@State var stats: [PlayerStat] = [
PlayerStat(id: 1, name: "Ale", wins: 9, losses: 4, points: 126, innings: 137, longRun: 6, lastAvg: 0.527),
PlayerStat(id: 2, name: "Luis", wins: 8, losses: 5, points: 153, innings: 125, longRun: 7, lastAvg: 0.427),
PlayerStat(id: 3, name: "Isabel", wins: 9, losses: 4, points: 126, innings: 152, longRun: 5, lastAvg: 0.623),
PlayerStat(id: 4, name: "Amy", wins: 10, losses: 2, points: 172, innings: 143, longRun: 4, lastAvg: 0.829),
PlayerStat(id: 5, name: "Daniel", wins: 3, losses: 2, points: 55, innings: 63, longRun: 9, lastAvg: 1.069)
]
var body: some View {
Table(stats, sortOrder: $sortOrder) {
TableColumn("Player", value: \.name)
TableColumn("W-L", value: \.wins) {stats in Text("\(stats.wins)" + " - " + "\(stats.losses)")}
TableColumn("Points", value: \.points) {stats in Text("\(stats.points)")}
TableColumn("Innings", value: \.innings) {stats in Text("\(stats.innings)")}
TableColumn("LR", value: \.longRun) {stats in Text("\(stats.longRun)")}
TableColumn("Avg", value: \.lastAvg) {stats in Text("\((stats.lastAvg), specifier: "%.3f")")}
}
.onChange(of: sortOrder) { newOrder in
stats.sort(using: newOrder) }
}
}
Thanks for any help.
The way I solved this problem was to use two SwiftUI files. the first file was like this:
@FetchRequest(sortDescriptors: []) var stats: FetchedResults<PlayerStats>
var body: some View {
Stats2View(stats: Array(stats))
}
}
The second file has most of your original code but adding one line.
// Add this
@State var stats:Array<PlayerStats>
@State private var sortOrder = [KeyPathComparator(\PlayerStats.name)]
var body: some View {
if #available(iOS 16.0, *) {
Table(stats, sortOrder: $sortOrder) {
TableColumn("Player", value: \.name!)
TableColumn("W-L", value: \.wins) {stats in Text("\(stats.wins)" + " - " + "\(stats.losses)")}
TableColumn("Points", value: \.points) {stats in Text("\(stats.points)")}
TableColumn("Innings", value: \.innings) {stats in Text("\(stats.innings)")}
TableColumn("LR", value: \.longRun) {stats in Text("\(stats.longRun)")}
TableColumn("Avg", value: \.lastAvg) {stats in Text("\((stats.lastAvg), specifier: "%.3f")")}
}
.onChange(of: sortOrder) { newOrder in
stats.sort(using: newOrder)}
}
else {...} \\old hacky lazyVGrid based table
}
}