15

I have this array of dictionaries.

let deckColors = [
    ["name": "blue", "desc": "desc1"],
    ["name": "yellow", "desc": "desc2"],
]

And my view:

struct ContentView: View {
    var body: some View {
        ForEach(0 ..< deckColors.count) {value in
            Text(deckColors[value]["name"])
        }
    }
}

How can I make it work? Currently getting this error: Protocol type Any cannot conform to StringProtocol because only concrete types can conform to protocols

0

3 Answers 3

14

This seems a very complex way to implement a struct:

struct DeckColor {
    var name: String
    var desc: String
}

let deckColors = [
    DeckColor(name: "blue", desc: "desc1"),
    DeckColor(name: "yellow", desc: "desc2")
]

struct ContentView: View {
    var body: some View {
        ForEach(0 ..< deckColors.count) { value in
            Text(deckColors[value].name)
        }
    }
}

The way you've implemented it requires dealing with the case that the dictionary does not include a "name" value. You can do that, but it's uglier and more fragile:

struct ContentView: View {
    var body: some View {
        ForEach(0 ..< deckColors.count) { value in
            Text(deckColors[value]["name"] ?? "default text if name isn't there.")
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

7

This works for me

struct ContentView: View {
    let deckColors = [
        ["name": "blue", "desc": "desc1"],
        ["name": "yellow", "desc": "desc2"],
    ]

    var body: some View {
        ForEach(0 ..< deckColors.count, id: \.self) {value in
            Text(String(self.deckColors[value]["name"]!))
        }
    }
}

Comments

1

I would put your deck colors into an enum and then iterate on that.

enum DeckColor: String, CaseIterable {
    case blue
    case yellow

    var desc: String {
        switch self {
            case .blue: return "desc1"
            case .yellow: return "desc2"
        }
    }
}

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            ForEach(DeckColor.allCases, id: \.self) { color in
                Text(color.rawValue)
            }
        }
    }
}

7 Comments

This would result in displaying the description instead of the color's name
I prefer what Rob Napier suggested. But anyways with this approach you would need to declare your enumeration as enum DeckColor: String, CaseIterable { and pass the color rawValue to the Text initializer. Text(color.rawValue)
The reason I suggested an enum over a struct is that with a struct, you have to run initialiser code every time your app runs, which gets more and more cumbersome the more ‘deckColors’ there are. If you want to access them throughout your app, you then either have to create them every time, or create a singleton of them. Enum’s give you public access, are static, and give you type-safety.
It all depends if OP will need to change them or not. If you have an enumeration this would not be possible.
The use of a dictionary from OP indicates that they might be hard-coding all the values in, but you make a very valid point.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.