iosswiftswiftuiswiftui-list

Looping sections with grouped values from model


I am attempting to place drugs under sections correlating to their class but I’m getting multiple sections for each drug I add of the same class. I’m not sure how much this process differs when using model macros.

Current Result

List {
    ForEach(activeStash) { drug in
        Section(header: Text(drug.substanceClass)) {
            NavigationLink(destination: StashLinkView(stashed: drug)) {
                Text(drug.substance)
            }
        }
    }
}

Grouping but with duped sections Result:

List {
    ForEach(activeStash) { drug in
        Section(header: Text(drug.substanceClass)) {
            ForEach(activeStash) { drug in
                NavigationLink(destination: StashLinkView(stashed: drug)) {
                    Text(drug.substance)
                }
            }
        }
    }
}

Solution:

List {
    ForEach(Array(Set(activeStash.map { $0.substanceClass })), id: \.self) { substanceClass in
        Section(header: Text(substanceClass)) {
            ForEach(activeStash.filter { $0.substanceClass == substanceClass }) { drug in
                NavigationLink(destination: StashLinkView(stashed: drug)) {
                    Text(drug.substance)
                }
            }
        }
    }
}

Solution

  • Your first ForEach needs to filter the available substance classes (the sections), the second filters drugs by their substance class to appear in the correct section:

    struct Drug: Identifiable, CustomStringConvertible {
        let substance: String
        let substanceClass: SubstanceClass
        
        let id: UUID = UUID()
        
        var description: String {
            "Drug: \(substance) (\(substanceClass))"
        }
    }
    
    enum SubstanceClass: String, CaseIterable, Identifiable {
        case stimulant = "Stimulant"
        case sedative = "Sedative"
        
        var id: String {
            self.rawValue
        }
    }
    
    struct ContentView: View {
        @State var substances: [Drug] = [
            Drug(substance: "Caffeine", substanceClass: .stimulant),
            Drug(substance: "Adrafinil", substanceClass: .stimulant),
            Drug(substance: "Valerian", substanceClass: .sedative)
        ]
        
        var body: some View {
            VStack {
                Text("Drug Store")
                List {
                    ForEach(SubstanceClass.allCases) { substanceClass in
                        Section(header: Text(substanceClass.rawValue)) {
                            ForEach(substances.filter({$0.substanceClass == substanceClass})) { drug in
                                NavigationLink(destination: Detail(drug: drug)) {
                                    Text(drug.substance)
                                }
                            }
                        }
                    }
                }
            }
            .padding()
        }
    }
    
    struct Detail: View {
        let drug: Drug
        
        var body: some View {
            Text(drug.description)
        }
    }
    

    I made up the model from what was available in your question.