Swift数据模型问题:无法筛选并计算盆景待办任务剩余天数
问题描述
我有两个Core Data模型:BonsaiModel和TaskModel,代码如下:
@Model final class BonsaiModel { var uuid: UUID var timestamp: Date var purchased: Date var price: Int var name: String var isFavorite: Bool var age: Int @Attribute(.externalStorage) var bonsaiImageData: Data? @Relationship(deleteRule: .nullify, inverse: \CategoryModel.bonsai) var category: CategoryModel? @Relationship(deleteRule: .nullify, inverse: \SpeciesModel.bonsai) var species: SpeciesModel? @Relationship(deleteRule: .cascade, inverse: \TaskModel.bonsai) var newTaskModel: [TaskModel] = [] @Relationship(deleteRule: .cascade, inverse: \BonsaiImageModel.bonsai) var bonsaiImages: [BonsaiImageModel] = [] init(name: String = "", isFavorite: Bool = false, bonsaiImageData: Data? = nil ) { self.uuid = UUID() self.timestamp = Date() self.purchased = Date() self.price = Int() self.name = name self.isFavorite = isFavorite self.age = 2023 self.bonsaiImageData = bonsaiImageData } } @Model final class TaskModel { var uuid: UUID var name: String var timestamp: Date var isComplete: Bool @Relationship(deleteRule: .nullify, inverse: \CareTypeModel.newTask) var careType: CareTypeModel? var isDue: Date var bonsai: BonsaiModel? init( name: String = "", isComplete: Bool = false ){ self.uuid = UUID() self.name = name self.timestamp = Date() self.isComplete = isComplete self.isDue = Date() } }
一个盆景可关联多个任务,当前功能运行正常。现在需要实现显示指定盆景的下一个待办任务的剩余天数。视图中获取数据的方式如下:
@Environment(\.locale) private var locale @State var bonsai = BonsaiModel() // 获取单个盆景实例 @Query private var taskModel: [TaskModel] // 获取所有任务
我的思路是先获取所有任务,筛选出属于指定盆景的任务,再获取isDue日期并计算该日期与当前日期的天数差,但使用filter方法时无法实现预期效果,求可行解决方案。
解决方案
方案1:直接利用Core Data关系获取关联任务
既然BonsaiModel已经通过newTaskModel关联了对应的TaskModel列表,完全不需要查询所有任务再筛选,直接从当前bonsai实例获取关联任务即可,效率更高:
// 从当前盆景实例筛选未完成的任务 let pendingTasks = bonsai.newTaskModel.filter { !$0.isComplete }
方案2:正确筛选全局任务列表(如果必须使用)
如果一定要用@Query获取的全局任务列表,筛选时需匹配盆景的uuid(Core Data对象直接比较可能存在问题,用唯一标识更可靠):
let targetBonsaiUUID = bonsai.uuid let pendingTasks = taskModel.filter { $0.bonsai?.uuid == targetBonsaiUUID && !$0.isComplete }
计算下一个待办任务的剩余天数
筛选出未完成任务后,找出isDue最早的任务,再计算与当前日期的天数差:
// 获取下一个待办任务(isDue最早的未完成任务) if let nextTask = pendingTasks.min(by: { $0.isDue < $1.isDue }) { let calendar = Calendar.current let components = calendar.dateComponents([.day], from: Date(), to: nextTask.isDue) if let remainingDays = components.day { // 根据剩余天数生成显示文本 let displayText = remainingDays > 0 ? "\(remainingDays)天后到期" : remainingDays == 0 ? "今天到期" : "\(-remainingDays)天已逾期" // 这里可以将displayText用于视图展示 } } else { // 无待办任务的处理逻辑 }
优化:用@Query直接过滤指定盆景的任务
可以在@Query中直接添加过滤条件,避免获取所有任务,提升性能:
// 替换原@Query,动态过滤当前盆景的未完成任务并按到期时间排序 @Query(filter: #Predicate<TaskModel> { task in task.bonsai?.uuid == bonsai.uuid && !task.isComplete }, sort: \TaskModel.isDue) private var pendingTasks: [TaskModel]
此时pendingTasks直接是当前盆景的未完成任务,且按到期时间升序排列,第一个元素就是下一个待办任务,直接取pendingTasks.first即可。
内容的提问来源于stack exchange,提问作者DennisHH
相关产品推荐
相关产品推荐

