How to properly group a list fetched from CoreData by date?

Update for iOS 15

SwiftUI now has built-in support for Sectioned Fetch Requests in a List via the @SectionedFetchRequest property wrapper. This wrapper reduces the amount of boilerplate required to group Core Data lists.

Example code

@Environment(\.managedObjectContext) var moc
@State private var date = Date()
@SectionedFetchRequest( // Here we use SectionedFetchRequest
  entity: Todo.entity(),
  sectionIdentifier: \.dateString // Add this line
  sortDescriptors: [
    SortDescriptor(\.date, order: .forward)
  ]
) var todos: SectionedFetchResults<Todo>

var body: some View {
    VStack {
      List {
        ForEach(todos) { (section: [Todo]) in
            Section(section[0].dateString!))) {
                ForEach(section) { todo in
                    HStack {
                        Text(todo.title ?? "")
                        Text("\(todo.date ?? Date(), formatted: todo.dateFormatter)")
                    }
                }
            }
        }.id(todos.count)
      }
      Form {
        DatePicker(selection: $date, in: ...Date(), displayedComponents: .date) {
          Text("Datum")
        }
      }
      Button(action: {
        let newTodo = Todo(context: self.moc)
        newTodo.title = String(Int.random(in: 0 ..< 100))
        newTodo.date = self.date
        newTodo.id = UUID()
        try? self.moc.save()
      }, label: {
        Text("Add new todo")
      })
    }

The Todo class can also be refactored to contain the logic for getting the date string. As a bonus, we can also use the .formatted beta method on Date to produce the relevant String.

struct Todo {
  
  ...

  var dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    return formatter
  }()

  var dateString: String? {
    formatter.string(from: date)
  }
}

Leave a Comment