按日期()将SWIFTUI列表中的CoreData分组为节 [英] Grouping CoreData by Date() in SwiftUI List as sections

查看:67
本文介绍了按日期()将SWIFTUI列表中的CoreData分组为节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标:

我希望能够按CoreData待办事项的过期范围对其进行分组。(今天&q;、明天&q;、未来7天&q;)

我尝试的内容.

我尝试使用@SectionedFetchRequest,但sectionIdentifier需要字符串。如果它作为日期()存储在CoreData中,我如何转换它以供使用呢?我收到了许多错误和建议,但都无济于事。这也不适用于日期范围,如&Quot;NEXT 7 DATE&QOOT;。此外,我似乎甚至没有访问实体的duedate,因为它指向我的ViewModel表单。

    @Environment(.managedObjectContext) private var viewContext
    
    //Old way of fetching Todos without the section fetch
    //@FetchRequest(sortDescriptors: []) var todos: FetchedResults<Todo>
    
    @SectionedFetchRequest<String, Todo>(
        entity: Todo.entity(), sectionIdentifier: Todo.dueDate,
        SortDescriptors: [SortDescriptor(.Todo.dueDate, order: .forward)]
    ) var todos: SectionedFetchResults<String, Todo>
Cannot convert value of type 'KeyPath<Todo, Date?>' to expected argument type 'KeyPath<Todo, String>'

Value of type 'NSObject' has no member 'Todo'

询问

有没有比@SectionedFetchRequest?更适合我的情况的解决方案。如果没有,我希望看到如何对数据进行适当分组。

推荐答案

您可以在entityextension中制作您自己的sectionIdentifier@SectionedFetchRequest

返回变量只需返回您的范围共有的内容,它才能正常工作。

extension Todo{
    ///Return the string representation of the relative date for the supported range (year, month, and day)
    ///The ranges include today, tomorrow, overdue, within 7 days, and future
    @objc
    var dueDateRelative: String{
        var result = ""
        if self.dueDate != nil{
            //Order matters here so you can avoid overlapping
            if Calendar.current.isDateInToday(self.dueDate!){
                result = "today"//You can localize here if you support it
            }else if Calendar.current.isDateInTomorrow(self.dueDate!){
                result = "tomorrow"//You can localize here if you support it
            }else if Calendar.current.dateComponents([.day], from: Date(), to: self.dueDate!).day ?? 8 <= 0{
                result = "overdue"//You can localize here if you support it
            }else if Calendar.current.dateComponents([.day], from: Date(), to: self.dueDate!).day ?? 8 <= 7{
                result = "within 7 days"//You can localize here if you support it
            }else{
                result = "future"//You can localize here if you support it
            }
        }else{
            result =  "unknown"//You can localize here if you support it
        }
        return result
    }
}

然后将其与您的@SectionedFetchRequest一起使用,如下所示

@SectionedFetchRequest(entity: Todo.entity(), sectionIdentifier: .dueDateRelative, sortDescriptors: [NSSortDescriptor(keyPath: Todo.dueDate, ascending: true)], predicate: nil, animation: Animation.linear)
var sections: SectionedFetchResults<String, Todo>

也查看this question

您也可以使用Date,但您必须选择一个日期作为节标题。在此方案中,您可以使用范围的上行日期,只使用日期而不是时间,因为如果它们不匹配,时间可能会创建其他部分。

extension Todo{
    ///Return the upperboud date of the available range (year, month, and day)
    ///The ranges include today, tomorrow, overdue, within 7 days, and future
    @objc
    var upperBoundDueDate: Date{
        //The return value has to be identical for the sections to match
        //So instead of returning the available date you return a date with only year, month and day
        //We will comprare the result to today's components
        let todayComp = Calendar.current.dateComponents([.year,.month,.day], from: Date())
        var today = Calendar.current.date(from: todayComp) ?? Date()
        if self.dueDate != nil{
            //Use the methods available in calendar to identify the ranges
            //Today
            if Calendar.current.isDateInToday(self.dueDate!){
                //The result variable is already setup to today
                //result = result
            }else if Calendar.current.isDateInTomorrow(self.dueDate!){
                //Add one day to today
                today = Calendar.current.date(byAdding: .day, value: 1, to: today)!
            }else if Calendar.current.dateComponents([.day], from: today, to: self.dueDate!).day ?? 8 <= 0{
                //Reduce one day to today to return yesterday
                today = Calendar.current.date(byAdding: .day, value: -1, to: today)!
            }else if Calendar.current.dateComponents([.day], from: today, to: self.dueDate!).day ?? 8 <= 7{
                //Return the date in 7 days
                today = Calendar.current.date(byAdding: .day, value: 7, to: today)!
            }else{
                today = Date.distantFuture
            }
        }else{
            //This is something that needs to be handled. What do you want as the default if the date is nil
            today = Date.distantPast
        }
        return today
    }
}

然后请求将如下所示.

@SectionedFetchRequest(entity: Todo.entity(), sectionIdentifier: .upperBoundDueDate, sortDescriptors: [NSSortDescriptor(keyPath: Todo.dueDate, ascending: true)], predicate: nil, animation: Animation.linear)
var sections: SectionedFetchResults<Date, Todo>

根据您提供的信息,您可以测试此代码,方法是将我提供的扩展粘贴到项目的.swift文件中,并将获取请求替换为您要使用的请求

这篇关于按日期()将SWIFTUI列表中的CoreData分组为节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆