[SOLVED] Generic enum Menu SwiftUI

Issue

I’m trying to create a View struct in SwiftUI for a menu view like the code below. I’m getting an error though with "Failed to produce diagnostic for expression; please submit a bug report". I don’t understand what I’m doing wrong.

To be clear, I would like to create a struct where I can just input an enum, a text string and an action for the button, and get back a Menu, to make the contentview more readable.

Hope you guys can help me. Cheers.

struct AddObjectMenuView<T: RawRepresentable, CaseIterable>: View {
    
    let labelText: String
    let someEnum: T
    let function: () -> Void
    
    var body: some View { // Getting error here
        Menu {
            ForEach(someEnum.allCases) { field in
                Button(action: function) {
                    VStack {
                        Text(field.rawValue).padding()
                    }
                }
            }
        } label: {
            Text(labelText).padding().background(RoundedRectangle(cornerRadius: 10).foregroundColor(.clear))
        }
        .foregroundColor(Color("lightBlue"))
    }
    
}

And then use it in my ContentView like this :

        AddObjectMenuView(labelText: "Hello", someEnum: SomeEnum, function: {
            // Do something
        })

Solution

You need to work with type of generics type to use .allCases.

Here is fixed variant (modified parts are highlighted inline). Tested with Xcode 13.2 / iOS 15.2

struct AddObjectMenuView<T: CaseIterable & Hashable> : View where T.AllCases: RandomAccessCollection {

    let labelText: String
    let someEnum: T.Type     // << here !!
    let function: () -> Void

    var body: some View {
        Menu {
            ForEach(someEnum.allCases, id: \.self) { field in   // << here !!
                Button(action: function) {
                    VStack {
                        Text(String(describing: field)).padding()  // << here !!
                    }
                }
            }
        } label: {
            Text(labelText).padding().background(RoundedRectangle(cornerRadius: 10).foregroundColor(.clear))
        }
        .foregroundColor(Color("lightBlue"))
    }
}

of course enums should be confirmed correspondingly.

And usage like

AddObjectMenuView(labelText: "Hello", someEnum: SomeEnum.self, function: {
    // Do something
})

Answered By – Asperi

Answer Checked By – Marie Seifert (BugsFixing Admin)

Leave a Reply

Your email address will not be published.