简体   繁体   English

任何 Identifiable 都不能符合“Identifiable”

[英]any Identifiable can't conform to 'Identifiable'

update: add same error about Hashable更新:添加关于 Hashable 的相同错误


I have created an Identifiable compliant protocol and compliant structures.我创建了一个可Identifiable的兼容协议和兼容结构。 Then, when I create the list and reference it in ForEach , I get the error Type 'any TestProtocol' cannot conform to 'Identifiable' (I get the same error about Hashable ).然后,当我创建列表并在ForEach中引用它时,我收到错误Type 'any TestProtocol' cannot conform to 'Identifiable' (我收到关于Hashable的相同错误)。

How should I fix this program?我应该如何修复这个程序?

If I write ForEach(list, id: \.id) , it works, but I don't think it makes sense to be Identifiable compliant.如果我写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")
            }
        }
    }
}

Your error message complaining about Hashable is a "red hering".您抱怨Hashable的错误消息是“红色的”。 The protocol TestProtocol , and therefor all structs conforming to it, conforms to Hashable .协议TestProtocol以及所有符合它的结构都符合Hashable

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

The reason this is failing is within the Picker .失败的原因是在Picker中。 It needs a concrete type and not a protocol.它需要具体类型而不是协议。 One solution would be to create a "Container" type and a custom binding that handles this.一种解决方案是创建“容器”类型和处理此问题的自定义绑定。

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

and the ContentView:和内容视图:

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

Remarks:评论:

This solution has a few drawbacks :该解决方案有一些缺点

  • your initial array startArr should never be empty, else return returninstance?? list[0]你的初始数组startArr不应该为空,否则return returninstance?? list[0] return returninstance?? list[0] will break you code. return returninstance?? list[0]会破坏你的代码。 This can be handled, but I think this is out of the scope of this question.这个是可以处理的,但我认为这超出了这个问题的scope。
  • the equality comparison of Container needs to be the same as in TestProtocol as you cannot compare two any Protocol s Container的相等性比较需要与TestProtocol中的相同,因为您无法比较两个any Protocol s
  • on the appearance of ContainerView selected will be nil until something is selected.在选择某些内容之前,在ContainerView的外观上selected将为零。 Any usage, eg: the Text element in this case, needs to deal with this.任何用法,例如:在这种情况下的Text元素,都需要处理这个问题。 But you could probably set this in .onApear .但是您可以在.onApear中设置它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Swift 枚举符合可识别:类型不符合可识别协议 - Swift enum conformance to identifiable: Type doesn't conform to Identifiable protocol 如何使数组符合“可识别” - How to conform an Array to 'Identifiable' Swift:不能使用采用 Identifiable 的协议 - Swift: can't use a protocol that adopts Identifiable Swift 协议类型“XXX”的值不能符合“可识别”; 只有结构/枚举/类类型可以符合协议 - Swift Value of protocol type 'XXX' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols SwiftUI 字符串符合 Identifiable 似乎不正确 - SwiftUI String conform Identifiable seems not correct SwiftUI Initialzier 要求 String 符合 Identifiable - SwiftUI Initialzier requires String conform to Identifiable ForEach 要求 '[String: String]' 符合 'Identifiable' - ForEach requires that '[String : String]' conform to 'Identifiable' 使结构符合可识别崩溃应用程序 - Making struct conform to Identifiable crashes app Model 是可散列和可识别的,但仍然不能使用 ForEach - Model is hashable and Identifiable but still can't use ForEach 如何使我的自定义 ViewModifier 仅适用于 SwiftUI 中符合(可识别和视图)的内容/视图? - How can I make my custom ViewModifier works only on Contents/Views that conform (Identifiable and View) in SwiftUI?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM