Search code examples
swiftswiftuiswiftui-listswift-dictionaryswiftui-view

Accessing values from a dictionary via a List selection in SwiftUI


I am thinking that this is probably quite simple to fix but I’ve not been able to find a solution so far.

I am trying to display a dictionary and allow the user to select an item so that I then have programatic access to both the keys and the values of their selection

I am able to display both the keys and values when listing the dictionary - e.g.

Text("Key:\t\t\(item)\t\t\t")
Text("Value:\t\(myList[item] ?? "")”)

but when the user makes a selection I am only able to access the key and print it, not display via a Text view

print("Selection is:\($selection)")

Not:

Text("Selection is:\(selection)")

or

Text("Selection is:\($selection)")

I am thinking that this could be related to my setting the selection variable as:

@State private var selection = Set<String>()

I have tried to configure it as:

@State private var selection = Set<String:String>()

but get error meessages for this.

Any advice would be much appreciated.

Full code is:

import SwiftUI

struct ContentView: View {
    
    var myList = ["Chumbawumba": "7", "Jini Dosa": "2", "Handbrake": "13"]
    
    @State private var selection = Set<String>()
    
    
    var body: some View {
        
        
        List(selection: $selection) {
            ForEach(myList.keys.sorted(), id: \.self) { item in
                
                HStack {
                    Text("Key:\t\t\(item)\t\t\t")
                    Text("Value:\t\(myList[item] ?? "")")
                    Spacer()
                }
            }
        }
        
//        Text("Selection is:")
//        Text(selection)
//        Text("Selection is:\(selection)")
        
        
        Button(action: {
            print("Selection is:\(selection)")
        }) {
            Text("Get")
                .padding()
        }
        .padding()
    }
}

Solution

  • As you've noted, selection contains only the selected keys, not values. To get the values, you need to use these keys to subscript your myList property like you do in the HStack. Here's an example:

    Button(action: {
        let selectedValues = selection
            .compactMap { myList[$0] }
            .joined(separator: ", ")
        print("Selection is: \(selectedValues)")
    }) {
        Text("Get")
            .padding()
    }
    

    I'm using compactMap here instead of map because the subscript returns an optional value, so this removes any nil values returned and gives us a list of non-optional strings.