0

Я храню список дней рождения в Core Data, и я использую NSFetchedResultsController, чтобы вернуть все дни рождения в Core Data. Главный вопрос, который у меня есть, - это год. Я хочу показать дни рождения, которые происходят через месяц. Но, как вы знаете, человек может родиться 18 октября 2005 года, но сравнение его с датой через месяц не сработает, потому что, предположив сегодня, 15 октября 2016 года я буду сравнивать 1 ноября 2016 года с 18 октября 2005 года поэтому мое приложение подумает, что день рождения не произойдет через месяц. Как проверить, происходит ли день рождения в следующем месяце с использованием NSPredicate?Верните все дни рождения, хранящиеся в базовых данных, которые происходят через 1 месяц

Вот код, я использую прямо сейчас без успеха:

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)") 
    } 
} 
} 

UPDATE: Теперь у меня есть представление о том, как справиться с этой проблемой. Либо месяц должен быть меньше или равен текущему месяцу плюс один, он может быть меньше, чем текущий месяц минус одиннадцать или месяц может быть одинаковым, а дата должна быть больше. Я пытался построить предикат для этого, но не кажется, что это будет работать:

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 
+1

Ваша проблема мне не ясна. Все даты рождения (живых людей) в прошлом, и все люди будут иметь день рождения в будущем. Итак, какие именно записи должны отображаться? Если сегодня 15 октября 2016 года, должно ли отображаться лицо, родившееся 1 апреля 2000 года, или нет? –

+0

@MartinR Хорошая точка. Возможно, я должен перефразировать мой вопрос. Как сортировать день рождения, чтобы день рождения, который уже был, дошел до конца массива? Имеет ли это смысл? В принципе, мой конечный результат состоит в том, чтобы иметь раздел, который показывает все дни рождения, следующие через неделю, а другой - дни рождения, следующие за 1 месяц, и игнорируют все другие дни рождения. Я отредактирую свой вопрос. – Harish

ответ

2

Если вы ищете для всех экземпляров повторяющегося события, как день рождения, которые происходят в течение следующей недели или month-- то атрибут «дата» не является хорошим выбором. Это будет, в лучшем случае, очень неудобно получить нужный вам результат. Дата в Core Data соответствует Swift Date, которая представляет собой мгновенное время и не хранит данные, такие как месяц или день месяца.

Было бы лучше сохранить эти данные в необходимой форме, например, с целыми значениями для месяца и дня. Это делает поиск довольно простым, так как у вас есть поля, в которых хранятся значения, которые необходимо использовать в качестве фильтров. В действительности нет хорошего способа использовать атрибут даты для того, что вам нужно. Плохой способ - рассчитать месячные интервалы за каждый прошлый год за последние N лет (за любой N, который вы выбрали) и построить массивный предикат, объединяющий все из них. Я не рекомендую.

Вам также придется обрабатывать специальный чехол на декабрь, где текущая дата может быть 12/18, а день рождения - 01/01. В этом случае он не обнаружит, что день рождения наступающий, поскольку 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 
+0

Спасибо за ваш ответ :)! Я согласен с вашим решением, но единственная проблема - скажем, что это 31 декабря (12/31), а день рождения - 1 января (01/01). Просто сравнение месяца не будет работать, потому что 12> 01. Существуют ли какие-либо решения для этого, о которых вы имеете в виду? – Harish

+0

Ваш код должен будет обрабатывать этот край. Если месяц - декабрь, тогда вам понадобится предикат, который учитывает два диапазона дат, в сочетании с логическим ИЛИ. –

+0

Согласовано, на самом деле мое решение было следующим: построить предикат, который определяет текущий месяц как Int, и что он делает, - это проверка, если месяц меньше 1 плюс текущий месяц или меньше 11 минус текущий месяц или месяц то же самое и дата больше текущей даты. Позвольте мне уточнить мой вопрос, чтобы сделать это более ясным. – Harish