Протоколы SwiftUI как тип: значение не может соответствовать «Идентифицируемому»; только типы struct / enum / class могут соответствовать протоколам

#swift #swiftui #swift-protocols

#быстрый #свифтуи #swift-протоколы

Вопрос:

Надеюсь, у вас у всех были замечательные каникулы. С новым годом!

Итак, я использую протоколы как тип:

 protocol Protocol_A_Or_B { }
protocol ProtocolA: Protocol_A_Or_B, Identifiable, Hashable, CaseIterable { }
protocol ProtocolB: Protocol_A_Or_B, Identifiable, Hashable, CaseIterable { }
 

Я удалил все переменные и функции из протоколов, поскольку считаю, что они не имеют отношения к проблеме, с которой я сталкиваюсь.

Я создал пару перечислений, которые реализуют либо ProtocolA или ProtocolB . Кроме того, у меня есть «основное перечисление», в котором есть метод, который возвращает массив объектов, который либо реализует ProtocolA , либо ProtocolB , для этого, ProtocolA и ProtocolB имеет «родительский» протокол ( Protocol_A_Or_B ).

 enum MainEnum_: Int, Identifiable, Hashable, CaseIterable {
    case One
    case Two
    case Three
    case Four
    case Five
    
    var id:Int { rawValue }
    
    var aOrBEnumArray: [Protocol_A_Or_B] {
        switch self {
        case .One:
            return EnumTypeA.allCases
        case .Two:
            return EnumTypeB.allCases
        default:
            return []
        }
    }
}

enum EnumTypeA: Int, ProtocolA {
    case Option1
    case Option2
    case Option3
    
    var id:Int { rawValue } 
}

enum EnumTypeB: Int, ProtocolB {
    case OptionA
    case OptionB
    case OptionC
    
    var id:Int { rawValue }
}
 

Пока все хорошо. Но когда я пытаюсь отправить массив объектов, которые реализуют Protocol_A_Or_B , я получаю следующие ошибки:

 Value of protocol type 'Protocol_A_Or_B' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols

Value of protocol type 'Protocol_A_Or_B' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols
 

Вот макет того View , где я использую объекты. Я получаю ошибки в строках кода TheContentView2(data: arrayEnumTypeA) и TheContentView2(data: arrayEnumTypeB) .

 struct EnumProtocolsTest: View {
    var arrayEnumTypeA: [Protocol_A_Or_B] = MainEnum_.One.aOrBEnumArray
    var arrayEnumTypeB: [Protocol_A_Or_B] = MainEnum_.Two.aOrBEnumArray
    
    var body: some View {
        VStack {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    TheContentView2(data: MainEnum_.allCases) { item in
                        Text("(item.name)")
                            .padding()
                            .background(Color.purple)
                    }
                }
            }
            
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    TheContentView2(data: arrayEnumTypeA) { item in
                        Text("(item.id)")
                            .padding()
                            .background(Color.purple)
                    }
                }
            }
            
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    TheContentView2(data: arrayEnumTypeB) { item in
                        Text("(item.id)")
                            .padding()
                            .background(Color.purple)
                    }
                }
            }
        }
    }
}
 

Итак, насколько я понимаю, я думаю, что ошибка связана с пользовательским представлением, которое у меня есть ( TheContentView2 ) , поскольку оно должно получать массив объектов, который реализует Identifiable и Hashable .

 struct TheContentView2<Data: RandomAccessCollection, ElementView: View>: View where Data.Element: Identifiable, Data.Element: Hashable {
    var data: Data
    var itemView: (Data.Element) -> ElementView
    
    var body: some View {
        ForEach(data) { item in
            itemView(item)
                .padding()
                .background(Color.purple)
        }
    }
}
 

Я не могу добавить свои протоколы как часть определения / подписи этого представления, но если это неверно, я могу запросить изменение.

Надеюсь, вы сможете мне помочь. Я не знаю, как я могу отправить массив объектов, которые реализуют родительский протокол ( Protocol_A_Or_B ). Не уверен, чего мне не хватает в определении протокола или в подписи пользовательского представления.

Спасибо!!!

Комментарии:

1. Похоже Protocol_A_Or_B , у него есть id свойство? Это единственное, что общего между ProtocolA и ProtocolB ?

2. Ошибки кажутся очевидными, вы не включили свой код протокола, но удалили наследование для Hashable и Identified из protocol_a_a_or_b . Вы можете включить переменную is, но не наследование.

3. @Sweeper, как упоминалось выше: я удалил все переменные и функции из протоколов, поскольку считаю, что они не имеют отношения к проблеме, с которой я сталкиваюсь. У Protocol_A_or_B есть свойство id, которое реализовано в перечислениях.

4. @loremipsum, если я добавлю наследование для идентифицируемого и хэшируемого в Protocol_A_Or_B, как вы упомянули, я получаю больше ошибок: «Protocol_A_Or_B может использоваться только как общее ограничение, поскольку оно имеет собственные или связанные требования к типу». Попробуйте.

5. @aнгел, ошибка на самом деле довольно описательная. ForEach (и из-за этого TheContentView2 ) требует соответствия Identifiable и Protocol_A_Or_B не соответствует ему (протоколы могут наследоваться только от протоколов, они не соответствуют протоколам). Таким образом, вы не можете [Protocol_A_Or_B] использовать массив таким образом. Если вам все еще требуются разные типы в одном массиве, прочитайте «удаление типа»