首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >协议类型'XXX‘的Swift值不能符合'Identifiable';只有struct/enum/class类型才能符合协议

协议类型'XXX‘的Swift值不能符合'Identifiable';只有struct/enum/class类型才能符合协议
EN

Stack Overflow用户
提问于 2020-12-30 16:16:28
回答 1查看 1.5K关注 0票数 1

我得到以下错误:

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

我有一个主菜单,它的一些选项有一个子菜单。我决定对主菜单使用一个enum,对任何子菜单使用另一个enum。所有枚举都实现了我定义的协议,它允许我为每个菜单选项指定要显示的文本。

我不确定这是否是最好的方法,但我发现它很有用。

有什么想法可以修复这个错误吗?谢谢你的帮忙!

代码语言:javascript
复制
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)
        }
    }
}
EN

回答 1

Stack Overflow用户

发布于 2020-12-30 20:56:35

ForEach需要一个Identifiable类型,这就是为什么你的菜单*-类型符合Identifiable。但是传递给ForEach的是一个不符合IdentifiableMenuProtocol

通常,当将对象(例如MainMenu)向上转换为基类或协议(在您的示例中为MenuProtocol)时,编译器只能访问该协议提供的属性/函数。这种限制是因为您可能还会传递符合协议的其他对象,但会遗漏所有其他属性,如本例中的id

在您的示例中,我认为没有理由为菜单提供面向协议的实现,因为您没有以多态的方式使用MainMenuSubMenu1。当涉及到协议、泛型和继承时,我的建议是:尽量保持简单,没有这些特性,如果不能解决问题,就添加这些特性。

关于面向协议的编程https://developer.apple.com/wwdc15/408 https://www.swiftbysundell.com/podcast/71/的好的WWDC视频和播客

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65503947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档