簡體   English   中英

Swift 協議類型“XXX”的值不能符合“可識別”; 只有結構/枚舉/類類型可以符合協議

[英]Swift Value of protocol type 'XXX' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols

我收到以下錯誤:

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

我有一個主菜單,其中一些選項有一個子菜單。 我決定對主菜單使用一個enum ,對任何子菜單使用另一個enum 所有枚舉都實現了我定義的協議,它允許我指定要為每個菜單選項顯示的文本。

我不確定這是否是最好的方法,但我發現它很有用。

任何想法如何解決此錯誤? 謝謝你的幫助!

Protocol MenuProtocol {
    var submenu: [OptionProtocol] { get }
}

protocol OptionProtocol {
    var name: String { get }
}

enum MainMenu: Int, Identifiable, CaseIterable, MenuProtocol, OptionProtocol {
    case One
    case Two
    case Three
    case Four
    case Five
    
    var id: Int { rawValue }
    
    var name: String {
        switch self {
        case .One:
            return "One"
        case .Two:
            return "Two"
        case .Three:
            return "Three"
        case .Four:
            return "Four"
        case .Five:
            return "Five"
        }
    }
    
    var submenu: [OptionProtocol] {
        switch self {
        case .One:
            return SubMenu1.allCases
        case .Two:
            return SubMenu2.allCases
        default:
            return []
        }
    }
}

enum SubMenu1: Int, Identifiable, CaseIterable, OptionProtocol {
    case SubMenu1_Option1
    case SubMenu1_Option2
    case SubMenu1_Option3
    case SubMenu1_Option4
    case SubMenu1_Option5
    
    var id: Int { rawValue }
    
    var name: String {
        switch self {
        case .SubMenu1_Option1:
            return "Submenu1 Option 1"
        case .SubMenu1_Option2:
            return "Submenu1 Option 2"
        case .SubMenu1_Option3:
            return "Submenu1 Option 3"
        case .SubMenu1_Option4:
            return "Submenu1 Option 4"
        case .SubMenu1_Option5:
            return "Submenu1 Option 5"
        }
    }
}

enum SubMenu2: Int, Identifiable, CaseIterable, OptionProtocol {
    case SubMenu2_OptionA
    case SubMenu2_OptionB
    case SubMenu2_OptionC
    case SubMenu2_OptionD
    case SubMenu2_OptionE
    
    var id: Int { rawValue }
    
    var name: String {
        switch self {
        case .SubMenu2_OptionA:
            return "Submenu2 Option A"
        case .SubMenu2_OptionB:
            return "Submenu2 Option B"
        case .SubMenu2_OptionC:
            return "Submenu2 Option C"
        case .SubMenu2_OptionD:
            return "Submenu2 Option D"
        case .SubMenu2_OptionE:
            return "Submenu2 Option E"
        }
    }
}

struct EnumProtTest: View {
    var body: some View {
        VStack {
            HStack {
                ForEach(MainMenu.allCases) { value in
                    Text("\(theName(value))")
                        .padding()
                        .background(Color.blue)
                }
            }
            
            HStack {
                TheContentView(data: MainMenu.One.submenu) { item in
                    Text("\(item.name)")
                        .padding()
                        .background(Color.purple)
                }
            }
            
            HStack {
                TheContentView(data: MainMenu.Two.submenu) { item in
                    Text("\(item.name)")
                        .padding()
                        .background(Color.purple)
                }
            }
        }
    }
}

struct TheContentView<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)
        }
    }
}

ForEach需要一個Identifiable類型,這就是您的 Menu*-types 符合Identifiable的原因。 但是傳遞給ForEach的是一個不符合IdentifiableMenuProtocol

通常,當將 object(例如MainMenu )向上轉換為基類或協議(在您的情況下MenuProtocol )時,編譯器只能訪問該協議提供的屬性/函數。 此限制是由於您還可以傳遞其他符合協議的對象,但在您的情況下會錯過所有其他屬性,例如id

在您的示例中,我沒有看到為菜單提供面向協議的實現的原因,因為您沒有以多態方式使用MainMenuSubMenu1 我對協議和 generics 和 inheritance 的建議是:盡量在沒有這些功能的情況下使其盡可能簡單,如果沒有這些功能就無法解決問題,請添加這些功能。

關於面向協議編程的優秀 WWDC 視頻和播客https://developer.apple.com/wwdc15/408 https://www.swiftbysundell.com/podcast/71/

您可以使用indices並使用索引檢索數據。 只需更改您的HStack

HStack {
    ForEach(MainMenu.One.items().indices) { index in
        let value = MainMenu.One.items()[index]
        Text(value.name())
            .padding()
            .background(Color.purple)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM