我使用 SwiftUI 的 ForEach 从视图模型中的矩阵绘制一个网格,该网格包含相同数量的行和列。我希望能够点击一个按钮并切换到一个新的矩阵,该矩阵具有不同长度的行和列(但仍然是方形网格)。 当我点击按钮并切换矩阵时,ForEach 会超出范围,同时尝试使用前一个网格的尺寸绘制较小的网格。
矩阵包含
RewardCell
元素,我已符合 Identifiable
和 Hashable
:
struct RewardCell: Identifiable {
var isVisible: Bool = false
let id: String = UUID().uuidString
let coord: CGPoint
}
extension RewardCell: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(isVisible)
}
static func == (lhs: RewardCell, rhs: RewardCell) -> Bool {
lhs.coord == rhs.coord
}
}
ForEach 强力通过矩阵,同时绘制它的视图,如下所示......
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
ForEach(rewards.grid, id: \.self) { row in
GridRow {
ForEach(row, id: \.self) { element in
RewardGridCell(coord: element.coord, isEditor: true)
.environmentObject(rewards)
}
}
}
}
上面使用的
rewards
ivar 是作为 ObservableObject
传入的 EnvironmentObject
,它以这种方式计算网格属性...
private lazy var muteableRewards: [Gift] = initialRewards
var currentReward: Gift {
get { muteableRewards[currentRewardIndex] }
set {
guard let index = muteableRewards.firstIndex(where: { $0 == newValue }) else { return }
currentRewardIndex = index
muteableRewards[index] = newValue
}
}
var grid: [[RewardCell]] { currentReward.unlockedTileMatrix }
它会像这样改变
currentRewardIndex
......
func nextIndex() {
currentRewardIndex = currentRewardIndex == rewards.count - 1 ? 0 : currentRewardIndex + 1
}
在
RewardGridCell
的构造函数内,它检查是否应该绘制它(isVisible
属性)并在下面的guard语句中抛出错误:
func isVisible(atCoord coord: CGPoint) throws -> Bool {
guard let value = element(atCoord: coord)?.isVisible else {
throw NullError(type: .optionalIsNil, subject: coord)
}
return value
}
func element(atCoord coord: CGPoint) -> RewardCell? {
for row in 0..<grid.count {
for column in 0..<grid[row].count {
if grid[row][column].coord == coord {
return grid[row][column]
}
}
}
return nil
}
绘制的第一个网格是5x5,第二个网格是3x3;当 ForEach 尝试坐标 (4,1) 时,它没有元素。我认为我搞砸了可识别一致性,或者也许我没有正确迭代多维数组。 为什么会发生这种情况?使用 SwiftUI 执行此操作的正确方法是什么?
如果需要,我可以添加更多信息,但我已经尝试包含相关代码。如果我在另一篇文章中错过了答案,或者在写问题时犯了一些错误,我真的很感激在任何反对票之前有一个链接或解释等等......
预先感谢您的时间和耐心。
只需删除所有出现的
id: \.self
和 Hashable
扩展名即可修复它。