我得到以下错误:
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)
}
}
}发布于 2020-12-30 20:56:35
ForEach需要一个Identifiable类型,这就是为什么你的菜单*-类型符合Identifiable。但是传递给ForEach的是一个不符合Identifiable的MenuProtocol。
通常,当将对象(例如MainMenu)向上转换为基类或协议(在您的示例中为MenuProtocol)时,编译器只能访问该协议提供的属性/函数。这种限制是因为您可能还会传递符合协议的其他对象,但会遗漏所有其他属性,如本例中的id。
在您的示例中,我认为没有理由为菜单提供面向协议的实现,因为您没有以多态的方式使用MainMenu和SubMenu1。当涉及到协议、泛型和继承时,我的建议是:尽量保持简单,没有这些特性,如果不能解决问题,就添加这些特性。
关于面向协议的编程https://developer.apple.com/wwdc15/408 https://www.swiftbysundell.com/podcast/71/的好的WWDC视频和播客
https://stackoverflow.com/questions/65503947
复制相似问题