Xcode报错:Referencing initializer ‘init(_:id:content:)’ on ‘ForEach’ requires that ‘ExpenseItem’ conform to ‘Hashable’
Xcode报错:Referencing initializer ‘init(_:id:content:)’ on ‘ForEach’ requires that ‘ExpenseItem’ conform to ‘Hashable’

Xcode报错:Referencing initializer ‘init(_:id:content:)’ on ‘ForEach’ requires that ‘ExpenseItem’ conform to ‘Hashable’

问题描述

在使用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)
}

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注