ios - 如何按日期正确对从 CoreData 获取的列表进行分组?

标签 ios swift core-data swiftui

为了简单起见,假设我想创建一个简单的待办事项应用程序。我的 xcdatamodeld 中有一个实体 Todo,其属性为 idtitledate,以及以下 swiftui View (如图所示):

import SwiftUI

struct ContentView: View {

  @Environment(\.managedObjectContext) var moc
  @State private var date = Date()
  @FetchRequest(
    entity: Todo.entity(),
    sortDescriptors: [
      NSSortDescriptor(keyPath: \Todo.date, ascending: true)
    ]
  ) var todos: FetchedResults<Todo>

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

  var body: some View {
    VStack {
      List {
        ForEach(todos, id: \.self) { todo in
          HStack {
            Text(todo.title ?? "")
            Text("\(todo.date ?? Date(), formatter: self.dateFormatter)")
          }
        }
      }
      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")
      })
    }
  }
}

待办事项在获取时按日期排序,并显示在如下列表中:

What I got

我想根据每个待办事项各自的日期对列表进行分组(模型):

What I want

根据我的理解,这可以与 init() 函数中的字典一起使用,但是我无法想出任何远程有用的东西。有没有一种有效的方法来对数据进行分组?

最佳答案

iOS 15 更新

SwiftUI 现在通过 @SectionedFetchRequest 属性包装器内置支持 List 中的分段提取请求。此包装器减少了对核心数据列表进行分组所需的样板数量。

示例代码

@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")
      })
    }

Todo 类也可以重构以包含获取日期字符串的逻辑。作为奖励,我们还可以在 Date 上使用 .formatted beta 方法来生成相关的 String

struct Todo {
  
  ...

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

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

关于ios - 如何按日期正确对从 CoreData 获取的列表进行分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59180698/

相关文章:

ios - 我如何知道 handleOpenURL 响应的文档类型?

iOS 在代码中创建 TableViewCell

ios - Sprite Kit 中玩家移动的最佳路径

swift - 快速动态转换类

swift - XIB View 的自动布局约束

objective-c - NSFetchedResultsController 在 performFetch 之后忽略 fetchLimit

ios - 如何使 Core Data 中的属性无效?

ios - "RCTBundleURLProvider.h"找不到文件 - AppDelegate.m

ios - ScrollView 对齐问题

iphone - CoreData 应用程序在执行获取请求时卡住 pthread_mutex_lock