5

I am trying to create SwiftUI List based on enum strings. I am faced with this error:

Cannot invoke initializer for type 'List<_, _>' with an argument list of type '([HomeView.Data], @escaping (String) -> HomeMenuRow)'

enter image description here

I can't understand how to use id or how to iterate through enum to build a row.

Matrosov Oleksandr
  • 25,505
  • 44
  • 151
  • 277
  • 1
    Can you post code _as text_? – Sweeper Apr 13 '20 at 12:04
  • Technically, your code works for me in Xcode 11.4. Share your non-working code to identify the exact problem. – staticVoidMan Apr 13 '20 at 12:16
  • yea looks like it works now. but now I get stuck on switch statement depend on is this .firsCase or another one I want to use different destination here NavigationLink(destination: LandmarkDetail()) but it's another question. thanks for help @staticVoidMan – Matrosov Oleksandr Apr 13 '20 at 12:24

2 Answers2

12

try this:

enum Whatever  : String, CaseIterable, Identifiable {

    var id : String { UUID().uuidString }

    case one = "one"
    case two = "two"
}

struct ContentView: View {
    var body: some View {
        VStack {
            List (Whatever.allCases) { value in
                Text(value.rawValue)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Chris
  • 7,579
  • 3
  • 18
  • 38
  • thanks, very strange, I just add .rawValue to my example and it works also. – Matrosov Oleksandr Apr 13 '20 at 12:09
  • On Xcode 12, this was crashing for me. I changed the `var id` to return `self.rawValue` instead and that resolved the issue for me. – Brian Bethke Nov 01 '20 at 02:22
  • 1
    There is a sideeffect to the enum code: retrieving the `id` of a `Whatever` will always generate a new UUID because of the call to `UUID()` in the getter. This can result in infinite loops when used e.g. within `ForEach(Whatever.allCases) { ... }` – Haensl Aug 06 '21 at 15:48
  • 1
    This answer contains a strong issue which is `Not Stable identifier`. Check out [this answer](https://stackoverflow.com/a/57411545/5623035) to see [How to confirm an enumeration to Identifiable protocol in Swift?](https://stackoverflow.com/a/57411545/5623035) – Mojtaba Hosseini Dec 13 '21 at 07:49
  • Why not use `rawValue` as id? It's unique enough. – bauerMusic Jan 14 '22 at 10:46
1

You don't need Identifiable here. I've added selections as well, because why not:

enum Whatever: String, CaseIterable {
    case one
    case two
}

struct ContentView: View {
  @Binding var selection: Whatever?


    var body: some View {
        VStack {
            List (Whatever.allCases, id: \.rawValue, selection: $selection) { item in
                Text(item.rawValue)
.tag(item)
            }
        }
    }
}

Selection has to be optional (the error messages here are not overly helpful), but this is basically how you get a list that changes an enum value. You can also use this for type erasure to display sublists of different data types in a sidebar (eg books, magazines, videos): use an enum with associated data, group by enum case, and enjoy. It is not necessary for id to be a static property; if your case is one(content: Book) you can have a computed id property with a switch statement and case one(let book): return book.id, and simply use an id: .id key path. (Unless elsewhere in Swift 5, the return keyword he remains mandatory).

green_knight
  • 1,319
  • 14
  • 26