![](/img/trans.png)
[英]Swift enum conformance to identifiable: Type doesn't conform to Identifiable protocol
[英]any Identifiable can't conform to 'Identifiable'
更新:添加關於 Hashable 的相同錯誤
我創建了一個可Identifiable
的兼容協議和兼容結構。 然后,當我創建列表並在ForEach
中引用它時,我收到錯誤Type 'any TestProtocol' cannot conform to 'Identifiable'
(我收到關於Hashable
的相同錯誤)。
我應該如何修復這個程序?
如果我寫ForEach(list, id: \.id)
,它可以工作,但我認為符合 Identifiable 沒有意義。
import SwiftUI
protocol TestProtocol: Identifiable, Hashable {
var id: UUID { get set }
var name: String { get set }
func greeting() -> String
static func == (lhs: Self, rhs: Self) -> Bool
}
extension TestProtocol {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.id == rhs.id
}
}
struct Person: TestProtocol {
var id = UUID()
var name: String
func greeting() -> String {
return "my name is \(name) and I'm a human."
}
}
struct Dog: TestProtocol {
var id = UUID()
var name: String
func greeting() -> String {
return "my name is \(name) and I'm a dog."
}
}
struct ContentView: View {
var list: [any TestProtocol] = [Person(name: "p1"), Dog(name: "d1")]
@State var selected: any TestProtocol
var body: some View {
VStack {
Picker(selection: $selected) { // Type 'any TestProtocol' cannot conform to 'Hashable'
ForEach(list) { l in // Type 'any TestProtocol' cannot conform to 'Identifiable'
Text(l.greeting()).tag(l) // Type 'any TestProtocol' cannot conform to 'Hashable'
}
} label: {
Text("select")
}
}
}
}
您抱怨Hashable
的錯誤消息是“紅色的”。 協議TestProtocol
以及所有符合它的結構都符合Hashable
。
let person = Person(name: "IAmHashable")
print(person.hashValue)
失敗的原因是在Picker
中。 它需要具體類型而不是協議。 一種解決方案是創建“容器”類型和處理此問題的自定義綁定。
struct Container: Identifiable, Hashable{
//implement the same equality as in your TestProtocol
static func == (lhs: Container, rhs: Container) -> Bool {
rhs.wrapped.id == lhs.wrapped.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(wrapped)
}
var wrapped: any TestProtocol
//for convenience
var id: UUID {wrapped.id}
}
和內容視圖:
struct ContentView: View {
let startArr: [any TestProtocol] = [Person(name: "p1"), Dog(name: "d1")]
@State private var selected: (any TestProtocol)?
var body: some View {
// list of wrapped protocols
var list: [Container] = { startArr.map{Container(wrapped: $0)}}()
// binding
let selectionBinding: Binding<Container> = .init {
let returninstance = list.first { cont in
cont.id == selected?.id
}
return returninstance ?? list[0]
} set: { container in
selected = container.wrapped
}
// viewCode
VStack {
Picker(selection: selectionBinding) {
ForEach(list) { l in
Text(l.wrapped.greeting())
.tag(l)
}
} label: {
Text("select")
}
// confirmation selection changed
Text(selected?.name ?? "no Selection")
}
}
}
該解決方案有一些缺點:
startArr
不應該為空,否則return returninstance?? list[0]
return returninstance?? list[0]
會破壞你的代碼。 這個是可以處理的,但我認為這超出了這個問題的scope。Container
的相等性比較需要與TestProtocol
中的相同,因為您無法比較兩個any Protocol
sContainerView
的外觀上selected
將為零。 任何用法,例如:在這種情況下的Text
元素,都需要處理這個問題。 但是您可以在.onApear
中設置它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.