We loop through categories, to create sections. Later on we loop through indices to actually display the content from Message struct.
import SwiftUI
struct MultipleSectionsView: View {
@State private var messages = [
Message(content: "Hello", category: .important, isSelected: false),
Message(content: "World", category: .significant, isSelected: false),
Message(content: "Hello", category: .important, isSelected: false),
Message(content: "World", category: .significant, isSelected: false),
Message(content: "Hello", category: .important, isSelected: false),
Message(content: "World", category: .pointless, isSelected: false)
]
var body: some View {
Form {
ForEach(Message.MessageCategory.allCases, id: \.self) { category in
Section(category.rawValue.uppercased()) {
ForEach(messages.indices, id:\.self) { index in
if messages[index].category == category {
HStack {
Image(
systemName:
messages[index].isSelected ? "checkmark.circle" : "circle"
)
Text(messages[index].content)
}
.onTapGesture {
messages[index].toggleSelection()
}
}
}
}
}
}
}
}
struct Message: Identifiable {
let id = UUID()
let content: String
let category: MessageCategory
var isSelected: Bool
mutating func toggleSelection() {
isSelected = !isSelected
}
enum MessageCategory: String, CaseIterable {
case pointless, important, significant
}
}In ForEach we need to use id. By using id we observe changes to the indices as well. Otherwise we could possibly get a crash by running out of bounds. You can test this out by simply adding messages = messages.dropLast() to the .onTapGesture closure and removing id:.self in the ForEach.

Not the most efficient solution, but I guess it does the job.
Homework: refactor code to a more efficient approach. At the moment we are looping through whole messages for each category. The solution should allow getting the data, without looping through messages for each category. Any other ideas for improvement?
