问题描述
在使用ForEach,通过id进行标识时:
ForEach(expense.items,id: \.self) { item in
Text(item.name)
}
输出下面的报错:
Referencing initializer 'init(_:id:content:)' on 'ForEach' requires that 'ExpenseItem' conform to 'Hashable'
经排查发现问题为,我的expense内的ExpenseItem结构没有实现Hashable协议,因此,我无法通过id进行标识每一个参数:
struct ExpenseItem {
var name: String
var type: String
var amount: Double
}
@Observable
class Expenses {
var items = [ExpenseItem]()
}
解决方案
解决方案1
给ExpenseItem实现Hashable协议。因此,应该将ExpenseItem修改为:
struct ExpenseItem: Hashable {
var name: String
var type: String
var amount: Double
}
这里我们需要知道,如果要在ForEach中使用id:\.self作为标识符,就必须要让ForEach的对象遵循Hashable协议,只有Hashable协议可以让我们的对象被唯一的哈希化。
解决方案2
另一个解决方案就是,如果你的类型没有实现Hashable协议,那么就不能使用id:\.self,但是我们可以指定其他的唯一标识符。比如我们这个ExpenseItem结构的name属性:
ForEach(expense.items, id: \.name) { item in
Text(item.name)
}
但是这里明确需要注意的是,我们指定其他的唯一标识符时,对应的标识符在需要是唯一的,否则可能会存在删除错误的情况。
当然,这个删除错误的情况没有在实际中浮现,因此建议遵循这一要求。
解决方案3
方案3为,让ExpenseItem结构遵循Identifiable协议,并设置一个id字段并生成一个UUID对象。
struct ExpenseItem: Identifiable {
var id = UUID()
let name: String
let type: String
let amount: Double
}
最后在ForEach当中,我们就不再需要手动指定id标识,直接使用ForEach:
ForEach(expense.items) { item in
Text(item.name)
}