I'm able to get a row item selected using onTapGesture
, and deselected if it is tapped again.
The question is why does the following code work, but the code shown at the end did not?
@Binding var selectedRow: RowItem?
var body: some View {
ForEach(modelData.rows) { row in
LazyVGrid(columns: columns) {
Text("text")
Text("text")
}
.onTapGesture {
if (selectedRow?.id == row.id) {
selectedRow = nil
} else {
selectedRow = row
}
}
}
}
where modelData.rows
is [RowItem]
,
and RowItem is: struct RowItem: Identifiable
and has an equality function defined:
static func == (lhs: RowItem, rhs: RowItem) -> Bool {
rhs.id == lhs.id
}
Why must the id
be used, and the following didn't work?
.onTapGesture {
if (selectedRow? == row) {
selectedRow = nil
} else {
selectedRow = row
}
}
(Fails with:)
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
The error "The compiler is unable to type-check this expression in reasonable time" is something you often see when a parenthesis is missing, or there is a typo, or you are trying to access a property that doesn't exist, or there is some other trivial error that most compilers would be able to spot without difficulty. But not Xcode.
When I tried your failing case with Xcode 16.1, the error was actually a bit more helpful:
Value of optional type 'RowItem?' must be unwrapped to a value of type 'RowItem'
This confusion is because the equality function is unnecessary. So you can begin by deleting the equality function. The error then changes to:
Operator function '==' requires that 'ContentView.RowItem' conform to 'Equatable'
This problem is fixed by specifically declaring that RowItem conforms to Equatable:
struct RowItem: Identifiable, Equatable { ...
The error then changes to:
'?' must be followed by a call, member lookup, or subscript
So the final fix is to remove the ?
. In Swift, you are allowed to compare an optional with a non-optional, the optional is automatically unwrapped if in fact it is not nil. Btw, you don't need to surround the expression with parentheses in Swift either:
.onTapGesture {
if selectedRow == row {
selectedRow = nil
} else {
selectedRow = row
}
}