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.
Post
Replies
Boosts
Views
Activity
I finally managed to have the last part of a 2.0 update to my app working fine. It involves a save view where the two players can attach their names to the stats of the last game just played.
As part of this view, I needed an auto suggest list under each of the textFields to appear as the players enter their names. This is so they don't have duplicate entries for variations of their names (for example, they might use "Daniel" or "Danny", but not sure which they used in the past).
It all worked great, EXCEPT that when I put the code for both autosuggest lists, the view became too unwieldy for Xcode to compile.
So: break into subviews. But, there is so much interconnected logic among all the pieces of the save screen that (given my very limited conceptual understanding of SwiftUI) I got horribly bogged down with @Bindings and passing parameters.
I did manage to break the autosuggest lists into their own subview (as a func). It now compiles (yay!). One little caveat, which is why I'm asking you for help. Here is (finally™) the ...
question:
Given the autosuggest list, I'd like the behavior to be that when the player taps on their name, the focus goes to the other player's textField. The FocusState is a Hashable enum called "FocusableField" with two cases (player1 and player2).
I'm having trouble changing the FocusState in the subview func. I tried to pass the FocusState var parameter as Binding<FocusableField> and as inout FocusableField, adding the appropriate $/&, but I get (respectively):
Cannot convert value of type 'FocusState<FocusableField?>.Binding' to expected argument type 'Binding'
and
Escaping closure captures 'inout' parameter 'focus'
Thanks for any help/suggestion.
I'm trying to create an auto-suggestion popover on a textField. In order to do that, I need to filter a string array based on characters already typed in textField (orangePlayerName). The data comes from a Core Data fetch (autoCompleteSuggestions.fetchNames()), to which I attach a .filter and .hasPrefix as follows:
ForEach(
autoCompleteSuggestions.fetchNames().filter{ $0?.hasPrefix(orangePlayerName) }, id: \.self) {...}
I get the following error:
Cannot convert value of type 'Bool?' to closure result type 'Bool'
Insert '!' [Fix]
If I insert the '!', then I get
Cannot force unwrap value of non-optional type 'Bool'
Remove '!' [Fix]
which is a fun Kafkian infinite loop of unfixable errors! Which I don't understand!
I appreciate any help on this.
(Also, too, if there is a better way to accomplish my goal, let me know. Searchable wouldn't work here because if the name is new, the user needs to be able to add their name. The reason I want to have the autosuggest is so that you don't get duplicates on variations of name of same person - like "Alejandro" or "alejandro" or "ale". If you start typing and see your name in the popover, you can just click on it and you are done.)
I have an app consisting of three paged tabviews. The center (main) view has two big buttons in the middle (hstacked). I'd like the buttons to be unresponsive to swipes (so that any touches there don't accidentally result in change of views).
I tried adding a .gesture(DragGesture()), but that didn't do anything. I also added GestureMask to that, but only the .all option made a difference, however it also (of course) disabled the needed tapping on the buttons.
This can't be a new problem, but I failed in my googling of it. Thanks for any help provided.
I'm embarrassed to say I haven't been able to google this successfully: I'm trying to save a couple of arrays of Int's (Int16 would be more than enough) as some of the attributes of a core data entity. The entity is basically a score box (like a baseball one) and it contains names of each player, and arrays for the number of points scored at each turn, among a few other standard attributes.
I'm pretty sure I need to make the array attributes Transformables. I don't know how to write the transformer. I thought I could maybe do the manual codegen, and then write some code to transform the int arrays into strings? Not sure. I can't imagine I'm the first person to try to tackle this problem, but I couldn't find anything anywhere that had a sample of something related to what I'm looking for.
If anyone could point me to a related resource, I'd really appreciate it.
Also, too, I'm a hopeless newbie.