Return 从现在起 1 个月后存储在 Core Data 中的所有生日

Return all birthdays stored in Core Data that occur 1 month from now

我在 Core Data 中存储生日列表,并且我在 Core Data 中使用 NSFetchedResultsController 到 return 所有生日。我遇到的主要问题是年份。我想显示一个月后的生日。但是如你所知,一个人可能出生于 2005 年 10 月 18 日,但将它与一个月后的日期进行比较是行不通的,因为假设今天是 2016 年 10 月 15 日,我会将 2016 年 11 月 1 日与 2005 年 10 月 18 日进行比较所以我的应用程序会认为生日不会在一个月后发生。如何使用 NSPredicate 检查下个月是否是生日?

这是我现在正在使用但没有成功的一些代码:

class BirthdayFetchedResultsController: NSFetchedResultsController<Birthday>, NSFetchedResultsControllerDelegate {

private let tableView: UITableView

init(managedObjectContext: NSManagedObjectContext, tableView: UITableView) {

    self.tableView = tableView

    let request: NSFetchRequest<Birthday> = Birthday.fetchRequest()


    let dateSortDescriptor = NSSortDescriptor(key: "date", ascending: true)
    request.sortDescriptors = [dateSortDescriptor]

    let startOfDay = Calendar.current.startOfDay(for: Date()) as NSDate

    // FIXME: The year matters here when it shouldn't.
    let predicate = NSPredicate(format: "date >= %@", startOfDay)
    request.predicate = predicate

    // TODO: Add section name key path for sorting the birthdays into sections
    super.init(fetchRequest: request, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    self.delegate = self

    tryFetch()
}

func tryFetch() {
    do {
        try performFetch()
    } catch let error as NSError {
        // TODO: Implement Error Handling
        print("Unresolved error: \(error), \(error.userInfo)")
    }
}
}

更新: 现在,我知道如何处理这个问题了。月份必须小于或等于当前月份加 1,可以小于当前月份减 11,或者月份可以相同但日期必须大于。我试图为此构建一个谓词,但它似乎不起作用:

let calendar = Calendar.current
let now = Date()
let month = calendar.component(.month, from: now)
let date = calendar.component(.day, from: now)

let predicate = NSPredicate(format: "((month <= %@) or (month <= %@)) or ((month == %@) AND (date >= %@))", argumentArray: [month + 2, month - 10, month, date])
request.predicate = predicate

如果您要查找在下周或下个月发生的生日等重复事件的所有实例,那么 "date" 属性不是一个好的选择。充其量,获得您需要的结果将是非常尴尬的。 Core Data 中的一个日期对应于一个 Swift Date,它代表一个瞬间并且不存储诸如月份或月份之类的详细信息。

最好以您需要的形式存储这些详细信息,例如月份和日期的整数值。这使得查找变得相当简单,因为您有存储需要用作过滤器的值的字段。确实没有什么好方法可以根据需要使用日期属性。一个糟糕的方法是计算过去 N 年的每一年的月份间隔(无论 N 你 select)并构建一个结合所有这些的大型谓词。不推荐。

您还必须处理 12 月的特殊情况,其中当前日期可能是 12 月 18 日,生日是 01 月 1 日。在这种情况下,它不会检测到生日即将到来,因为 12 > 1.

这是一个示例谓词:

    // Month Conditions
    let monthCondition1 = NSPredicate(format: "month <= %i", month + 1)
    let monthCondition2 = NSPredicate(format: "month > %i", month)
    let monthConditions = NSCompoundPredicate(andPredicateWithSubpredicates: [monthCondition1, monthCondition2])

    // Date Conditions
    let dateCondition1 = NSPredicate(format: "month == %i", month)
    let dateCondition2 = NSPredicate(format: "date >= %i", date)
    let dateConditions = NSCompoundPredicate(andPredicateWithSubpredicates: [dateCondition1, dateCondition2])

    // Special Month Condition - Example: If currentDate is 12/31 and the birthday is 01/01 current month is greater than birthday but we still show it.

    var predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [monthConditions, dateConditions])

    if month == 12 {
        let specialMonthCondition1 = NSPredicate(format: "month == %i", 1)
        predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate, specialMonthCondition1])
    }

    request.predicate = predicate