gpt4 book ai didi

swift - any Identifiable 不能符合 'Identifiable'

转载 作者:行者123 更新时间:2023-12-05 05:33:40 30 4
gpt4 key购买 nike

更新:添加关于 Hashable 的相同错误


我已经创建了一个 Identifiable 兼容协议(protocol)和兼容结构。然后,当我创建列表并在 ForEach 中引用它时,我收到错误 Type 'any TestProtocol' cannot conform to 'Identifiable'(我收到关于 的相同错误code>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 的错误消息是一个“red hering”。协议(protocol) TestProtocol 以及所有符合它的结构都符合 Hashable

let person = Person(name: "IAmHashable")
print(person.hashValue)

失败的原因在于 Picker。它需要一个具体的类型而不是一个协议(protocol)。一种解决方案是创建“容器”类型和处理此问题的自定义绑定(bind)。

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}
}

和内容 View :

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] 会破坏你的代码。这可以处理,但我认为这超出了这个问题的范围。
  • Container 的相等性比较需要与 TestProtocol 中的相同,因为您不能比较两个 any Protocol
  • ContainerView 的外观上 selected 将是 nil,直到选择了某些东西。任何用法,例如:本例中的 Text 元素,都需要处理这个问题。但是您可以在 .onApear 中设置它。

关于swift - any Identifiable 不能符合 'Identifiable',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73773884/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com