Home > Software engineering >  Loop through any Array of NSDictionaries to make a list?
Loop through any Array of NSDictionaries to make a list?

Time:07-28

I am working on a Swift project where I need to display an array of dictionaries in a List. I cannot get the formatting to work in keep running into random errors like it's not expecting a [NSDictionary] type of binding errors.

My array is like so:

items = [{"name": "jack"}, {"name" : "joe"}, {"name" : "john"}]

Where each dictionary is an NSDictionary. I tried doing some sort of List{ ForEach()} but that also wasn't working. I feel like this data set-up is pretty common, and looping through the list of dictionaries to complete a list shouldn't be too hard.

        List(items) {item in
            Text(items.name)
        }

Something as simple as this I've seen work elsewhere, but gives me an error of:

Cannot convert value of type '[NSDictionary]' to expected argument type 'Binding<Data>'
Generic parameter 'Data' could not be inferred
Initializer 'init(_:)' requires that 'Binding<Subject>' conform to 'StringProtocol'

CodePudding user response:

Isn't that a typo? It should be item.name instead of items.name. Items is the list itself, you are suppose to past the item object to the UI.

List(items) {item in
    Text(item.name)
}

CodePudding user response:

You could try this approach, as shown in the example code in SwiftUI. Since you require an array of dictionaries, you need 2 ForEach loops, one over the array of dictionaries, and one over the keys of a particular dictionary.

Note, it is somewhat simpler if you use Dictionary instead of NSDictionary.

struct ContentView: View {
    @State var items: [NSDictionary] = [["name" : "jack"], ["name" : "joe"], ["name" : "john"]] 
    
    var body: some View {
        List {
            ForEach(items, id: \.self) { item in  // <-- loop over the dictionaries
                ForEach(item.allKeys as! [String], id: \.self) { key in // <-- loop over dictionary keys
                    Text(item[key] as? String ?? "")
                }
            }
        }
    }
}

If you are only going to have "name" as the only key in the dictionary, then you can use this:

    List {
        ForEach(items, id: \.self) { item in
            Text(item["name"] as? String ?? "")
        }
    }

Another approach, if you have only name as key:

struct ContentView: View {
    @State var items: [NSDictionary] = [["name" : "jack"], ["name" : "joe"], ["name" : "john"]]
    
    var body: some View {
        List(items.compactMap{ ($0.allValues.first as? String)}, id: \.self) { name in
            Text(name)
        }
    }
}

Using a Dictionary such as [String:String]:

struct ContentView: View {
    @State var items = [["name" : "jack"], ["name" : "joe"], ["name" : "john"]]
    
    var body: some View {
        List(items, id: \.self) { item in
            Text(item["name"] ?? "")
        }
    }
}
  • Related