【问题标题】:Swift: Sorting Core Data child entities on fetch based on DateSwift:基于日期对核心数据子实体进行排序
【发布时间】:2018-10-10 13:07:57
【问题描述】:

简介

我正在制作一个日历应用程序,我使用 Core Data 在其中存储事件。

其组成:DateKey 作为父级(具有一对多关系)到CalendarEventModel。这个概念是DateKey 拥有一个 yyyy-dd-MM 日期字符串,并且当天发生的所有事件都作为子项添加到 DateKey 中作为 NSOrderedSet 中的CalendarEventModel。 (我使用的是类定义,没有一个实体是抽象的。)。 CalendarEventModel 是包含有关一个日历事件的信息的实体。

我试图完成的事情

一切都按预期工作,只是我无法对获取的结果进行排序。当我获取与当前日历相关的 DateKeys 时,我根本无法让它们像这样排序:

我想在 CalendarEventModels 属性startDate 之后按升序($0.startDate isAllDay = false,然后再标记为 isAllDay = true

问题/疑问

  • 我在下面代码的注释中做了一些澄清。
  • 我无法让 NSSortDescriptor 正常工作(我的尝试在下面的代码中进行了注释
  • 我已经阅读了关于 DateKey 的 calendarEvents 属性的 NSOrderedSet,但我还没有找到如何将它用于我的排序标准。

你会如何解决这个排序问题? 如果需要更多信息,请告诉我。

我的代码

fileprivate func loadEventsFromCoreData() {

    dateFormatter.dateFormat = "yyyy dd MM"
    let startDate = Date()
    var predicatesForFetch : [NSPredicate] = []
    var dateStringArray : [String] = []
    var fetchResultsArray : [DateKey]?

    for num in 0...9 {
        let newDate = startDate.add(TimeChunk(seconds: 0, minutes: 0, hours: 0, days: num, weeks: 0, months: 0, years: 0))
        let datePredicate = dateFormatter.string(from: newDate)
        dateStringArray.append(datePredicate)
        predicatesForFetch.append(NSPredicate(format: "dateInfo == %@", datePredicate))
    }
    setupSectionArray(eventArray: dateStringArray)

    // I'm getting the correct DateKeys and their events.

    let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicatesForFetch)
    let eventFetch : NSFetchRequest<DateKey> = DateKey.fetchRequest()
    eventFetch.predicate = compoundPredicate

    // I've tried specifying this sortDescriptor and added it to the eventFetch: 
    //   let descriptor = NSSortDescriptor(key: "calendarEvents", ascending: true) { ($0 as! CalendarEventModel).startDate!.compare(($1 as! CalendarEventModel).startDate!) }
    //   let sortDescriptors = [descriptor]
    //   eventFetch.sortDescriptors = sortDescriptors

        do {
            fetchResultsArray = try coreDataContext.fetch(eventFetch)

        } catch {
            print("Core Data initial fetch failed in Calendar Controller: \(error)")
        }

    guard fetchResultsArray != nil else { return }

    // Xcode doesn't recognize the .sort() function which does not have a return value... and I don't think its a good idea to use the return function at all since I will have to delete all children and re add the sorted for each fetch.

    for eventArray in fetchResultsArray! {
        eventArray.calendarEvents?.sorted(by: { ($0 as! CalendarEventModel).startDate!.compare(($1 as! CalendarEventModel).startDate!) == .orderedAscending })
        eventArray.calendarEvents?.sorted { ($0 as! CalendarEventModel).isAllDay && !($1 as! CalendarEventModel).isAllDay }

    }

    events = fetchResultsArray!
}

感谢您阅读我的问题。

【问题讨论】:

    标签: ios swift sorting core-data


    【解决方案1】:

    一些注意事项:

    • 基本上你不能以字符串格式"yyyy dd MM"对日期进行排序,要么使用"yyyy MM dd",要么——强烈推荐——Date类型。
    • 您无法就地对关系进行排序。一对多关系是无序的Sets。顺便将关系声明为原生 Set&lt;CalendarEventModel&gt; 而不是未指定的 NSSet 并且是非可选的。
    • 不要使用复合谓词,使用 one 谓词并且不要获取 DateKey 记录,获取带有谓词 dateKey.dateInfo &gt;= startDate &amp;&amp; dateKey.dateInfo &lt;= endDateCalendarEventModel 记录并在其中添加两个排序描述符。

    一次获取过滤和排序的记录比获取关系项并手动进行排序效率更高。

    编辑:

    要获得今天的午夜和 + 9 天使用

    let calendar = Calendar.current
    let now = Date()
    let nowPlus9Days = calendar.date(byAdding: .day, value: 9, to: now)!
    let startDate = calendar.startOfDay(for: now)
    let endDate = calendar.startOfDay(for: nowPlus9Days)
    

    此代码获取日期范围内所有已排序的 CalendarEventModel,并将数组分组到 [Date : [CalendarEventModel]] 字典中

    let predicate = NSPredicate(format: "dateKey.dateInfo >= %@ && dateKey.dateInfo <= %@", startDate as CVarArg, endDate as CVarArg)
    let sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: true), NSSortDescriptor(key: "isAllDay", ascending: true)]
    
    let eventFetch : NSFetchRequest<CalendarEventModel> = CalendarEventModel.fetchRequest()
    eventFetch.predicate = predicate
    eventFetch.sortDescriptors = sortDescriptors
    do {
        let fetchResultsArray = try coreDataContext.fetch(eventFetch)
        let groupedDictionary = Dictionary(grouping: fetchResultsArray, by: {$0.startDate})
    
    } catch {
        print("Core Data initial fetch failed in Calendar Controller: \(error)")
    }
    

    不要在catch 块之后执行代码。将所有 good 代码放在 fetch 之后的 do 范围内。

    【讨论】:

    • 感谢您的回答。这说得通。但是我将 DateKey 中的 CalendarEventModel 实体保存为 dateInfo 等于 CalendarEventModel.startDate。因为我每天都需要[CalendarEventModel] 才能在日历视图的不同部分使用它们,所以我需要[Date : [CalendarEventModel]] 类型的它们。因此,回顾一下,您是否建议我获取CalendarEventModel 记录并将它们存储在我的视图控制器类型的变量中:[Date : [CalendarEventModel]] 其中日期应该代表DateKey.dateInfo of the [CalendarEventModel]` 父级?
    • 另外 1. 我在哪里/如何声明像 Set&lt;CalendarEventModel&gt; 这样的关系? 2. 你介意写一个 NSPredicate 的例子吗?我需要获取“今天日期”和接下来 9 天的所有 CalendarEventModel 记录。而且我不知道如何格式化它。
    • 再一次,如果日期字符串格式为yyyy dd MM,则模型无论如何都无法工作,因为它不可排序。我强烈建议使用Date 而不是String。您可以在NSManagedObject 子类中更改Set 类型。
    • 是的,我听取了您的建议,并将 dateInfo 更改为 Date 类型。啊,当然,谢谢。但我仍然坚持格式化该谓词,如何获取正确日期的 CalendarEventModel 对象(Date() 和 9 天前),以及格式化 NSSortDescriptor。稍微推动一下格式化这些内容。
    • 正常工作。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多