Swift:根据日期对获取时的Core Data子实体进行排序 [英] Swift: Sorting Core Data child entities on fetch based on Date

查看:103
本文介绍了Swift:根据日期对获取时的Core Data子实体进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm making a calendar app in which I store events using Core Data.

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

Its composed of: DateKey as the parent (with a one-to-many relationship) to CalendarEventModel. The concept is that DateKey holds a yyyy-dd-MM date string and all events that occur that day are added as a child to that DateKey as CalendarEventModel in a NSOrderedSet. (I'm using Class Definition, none of the entities are abstract.). CalendarEventModel being the entity containing information about one calendar event.

我要完成的任务

一切都按预期进行,除了我无法对获取的结果进行排序.当我获取与当前日历相关的DateKeys时,我简直无法让它们像这样进行排序:

Everything works as intended except that I can't sort my fetched results. When I fetch the DateKeys relevant for the current Calendar I simply can't get them to sort like this:

我想对CalendarEventModels属性startDate之后的每个DateKey中的CalendarEventModel进行升序排序($ 0.startDate< $ 1.startDate).然后,在带有isAllDay = true的CalendarEventModels之前标记为isAllDay = false.

I want to sort the CalendarEventModel in each DateKey after the CalendarEventModels attribute startDate in ascending order ($0.startDate < $1.startDate). Then have the CalendarEventModels marked isAllDay = false before those with isAllDay = true.

问题/问题

  • 在下面的代码中,我在注释中做了一些澄清.
  • 我无法让NSSortDescriptor正常工作(我的尝试在下面的代码中得到注释
  • 我已经了解了DateKey的calendarEvents属性是NSOrderedSet,但是我还没有找到如何将其用于排序标准.
  • I've put some clarifications in comment in the code below.
  • I can't get NSSortDescriptor to work properly ( my attempt is commented in the code below
  • I've read about NSOrderedSet which the calendarEvents attribute of DateKey is, but I haven't found out how to use it for my sorting criteria.

您将如何解决这种排序? 让我知道是否需要更多信息.

How would you solve this sorting? Let me know if more information is needed.

我的代码

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!
}

感谢您阅读我的问题.

推荐答案

一些注意事项:

  • 基本上,您不能使用"yyyy MM dd"或-强烈建议-Date类型的字符串格式对日期进行排序.
  • 您无法对关系进行分类.一对多关系是无序的Set.顺便说一句,将关系声明为本机Set<CalendarEventModel>而不是未指定的NSSet且为非可选.
  • 不要使用复合谓词,使用一个谓词,不要获取DateKey记录,不要获取具有谓词dateKey.dateInfo >= startDate && dateKey.dateInfo <= endDateCalendarEventModel记录,并在其中添加两个排序描述符./li>
  • Basically you cannot sort dates in string format "yyyy dd MM", either use "yyyy MM dd" or – highly recommended – Date type.
  • You cannot sort a relationship in place. To-many relationships are Sets which are unordered. By the way declare the relationship as native Set<CalendarEventModel> rather than unspecified NSSet and as non-optional.
  • Don't use a compound predicate, use one predicate and don't fetch DateKey records, fetch CalendarEventModel records with predicate dateKey.dateInfo >= startDate && dateKey.dateInfo <= endDate and add there the two sort descriptors.

一次获取经过过滤和排序的记录比获取关系项并手动对其进行排序要有效得多.

Fetching filtered and sorted records once is much more efficient than get the relationship items and sort them manually.

要获取今天的午夜和+ 9天的使用时间

To get midnight of today and + 9 days use

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]]字典

This code fetches all sorted CalendarEventModel in the date range and groups the array to a [Date : [CalendarEventModel]] dictionary

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 代码.提取后,将所有 good 代码放入do范围.

Don't execute good code after the catch block. Put all good code in the do scope after the fetch.

这篇关于Swift:根据日期对获取时的Core Data子实体进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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