使用 CoreData 如何配置获取请求以查找即将到来的生日?
Using CoreData how to configure a fetch request to find upcoming birthdays?
我正在使用 Xcode 7.3 和 Swift 2.2 以及 NSFetchedResultsController
。是否可以创建使用谓词和排序描述符配置的所需提取请求来解决此问题?
给定一个具有 birthDate
属性的 Person
实体,我该如何配置对 return 即将到来的生日的提取请求?这是我尝试过的:
我创建了一个名为 birthDateThisYear
的临时属性,并将其配置为 return 这个人今年的生日。但是我发现你不能在 Core Data 的获取请求中使用瞬态属性。
我通过使用 birthDateDayNumber
和 birthDateMonthNumber
属性以及 birthDate
的自定义 setter 进行反规范化来尝试接受的答案 here但我无法弄清楚谓词。如果今天是 12 月 31 日怎么办?不知何故,它需要环绕以包括一月、二月和三月。
我读到可以用表达式和比较谓词来完成。但我想不出解决办法。有人成功了吗?
我认为创建一个名为 birthDateInYear2000
的非规范化属性是可行的,但同样,它也遇到了同样的重叠问题。
有什么想法吗?
建议:
- 获取所有个生日。
从现在开始将生日映射到下一个日期
let calendar = NSCalendar.currentCalendar()
let nextBirthDays = birthdays.map { (date) -> NSDate in
let components = calendar.components([.Day, .Month], fromDate: date)
return calendar.nextDateAfterDate(NSDate(), matchingComponents: components, options: .MatchNextTime)!
}
对日期进行排序
let sortedNextBirthDays = nextBirthDays.sort { [=11=].compare() == .OrderedAscending }
现在 sortedNextBirthDays
包含所有即将到来的生日,并按升序排列。
在 Core Data 中,您可以获取包含生日和对象 ID(或全名)的字典形式的记录,创建一个临时结构,映射和排序项目并获取对象 ID 的人(或使用全名)——或者您甚至可以将逻辑应用于 NSManagedObject
数组
编辑
如果有关下一个生日的信息存储在持久存储中(假设它是MySQL-store),因为您不能应用排序描述符,包括指向瞬态或计算属性的键。
更新 nextBirthDate
属性 的最佳位置是在创建视图控制器的 NSFetchedResultsController
实例之前。
- 在实体
Person
中创建一个(可选)属性 nextBirthDate
创建 NSDate
的扩展以计算从现在开始的下一次日期
extension NSDate {
var nextOccurrence : NSDate {
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Day, .Month], fromDate: self)
return calendar.nextDateAfterDate(NSDate(), matchingComponents: components, options: .MatchNextTime)!
}
}
在闭包中初始化 NSFetchResultsController
实例添加代码以更新每个记录的 nextBirthDate
属性
lazy var fetchedResultsController: NSFetchedResultsController = {
let fetchRequest = NSFetchRequest(entityName: "Person")
do {
let people = try self.managedObjectContext.executeFetchRequest(fetchRequest) as! [Person]
people.forEach({ (person) in
let nextBirthDate = person.birthDate.nextOccurrence
if person.nextBirthDate == nil || person.nextBirthDate! != nextBirthDate {
person.nextBirthDate = nextBirthDate
}
})
if self.managedObjectContext.hasChanges {
try self.managedObjectContext.save()
}
} catch {
print(error)
}
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptors = [NSSortDescriptor(key:"nextBirthDate", ascending: true)]
fetchRequest.sortDescriptors = sortDescriptors
...
如果视图控制器可以编辑 birthDate
属性 不要忘记更新 nextBirthDate
属性 以及保持视图同步。
我的建议类似:
- 获取全部customers/persons
- 筛选出今天之前 3 天和之后 3 天范围内的所有生日
像下面这样使用闭包:
func fetchBirthdayList(){
// this example considers all birthdays that are like
// |---TODAY---|
// Each hyphen represents a day
let date = Date()
let timeSpan = 3
let cal = Calendar.current
nextBirthDays = self.list.filter { (customer) -> Bool in
if let birthDate = customer.birthDate {
let difference = cal.dateComponents([.day,.year], from: birthDate as! Date, to: date)
return (( (difference.day! <= timeSpan) || ((365 - difference.day!) <= timeSpan) ) && difference.day! >= 0)
}
return false
}
}
如果你想要,你可以在之后订购结果。
干杯
奥利弗
我正在使用 Xcode 7.3 和 Swift 2.2 以及 NSFetchedResultsController
。是否可以创建使用谓词和排序描述符配置的所需提取请求来解决此问题?
给定一个具有 birthDate
属性的 Person
实体,我该如何配置对 return 即将到来的生日的提取请求?这是我尝试过的:
我创建了一个名为
birthDateThisYear
的临时属性,并将其配置为 return 这个人今年的生日。但是我发现你不能在 Core Data 的获取请求中使用瞬态属性。我通过使用
birthDateDayNumber
和birthDateMonthNumber
属性以及birthDate
的自定义 setter 进行反规范化来尝试接受的答案 here但我无法弄清楚谓词。如果今天是 12 月 31 日怎么办?不知何故,它需要环绕以包括一月、二月和三月。我读到可以用表达式和比较谓词来完成。但我想不出解决办法。有人成功了吗?
我认为创建一个名为
birthDateInYear2000
的非规范化属性是可行的,但同样,它也遇到了同样的重叠问题。
有什么想法吗?
建议:
- 获取所有个生日。
从现在开始将生日映射到下一个日期
let calendar = NSCalendar.currentCalendar() let nextBirthDays = birthdays.map { (date) -> NSDate in let components = calendar.components([.Day, .Month], fromDate: date) return calendar.nextDateAfterDate(NSDate(), matchingComponents: components, options: .MatchNextTime)! }
对日期进行排序
let sortedNextBirthDays = nextBirthDays.sort { [=11=].compare() == .OrderedAscending }
现在
sortedNextBirthDays
包含所有即将到来的生日,并按升序排列。
在 Core Data 中,您可以获取包含生日和对象 ID(或全名)的字典形式的记录,创建一个临时结构,映射和排序项目并获取对象 ID 的人(或使用全名)——或者您甚至可以将逻辑应用于 NSManagedObject
数组
编辑
如果有关下一个生日的信息存储在持久存储中(假设它是MySQL-store),因为您不能应用排序描述符,包括指向瞬态或计算属性的键。
更新 nextBirthDate
属性 的最佳位置是在创建视图控制器的 NSFetchedResultsController
实例之前。
- 在实体
Person
中创建一个(可选)属性 创建
NSDate
的扩展以计算从现在开始的下一次日期extension NSDate { var nextOccurrence : NSDate { let calendar = NSCalendar.currentCalendar() let components = calendar.components([.Day, .Month], fromDate: self) return calendar.nextDateAfterDate(NSDate(), matchingComponents: components, options: .MatchNextTime)! } }
在闭包中初始化
NSFetchResultsController
实例添加代码以更新每个记录的nextBirthDate
属性lazy var fetchedResultsController: NSFetchedResultsController = { let fetchRequest = NSFetchRequest(entityName: "Person") do { let people = try self.managedObjectContext.executeFetchRequest(fetchRequest) as! [Person] people.forEach({ (person) in let nextBirthDate = person.birthDate.nextOccurrence if person.nextBirthDate == nil || person.nextBirthDate! != nextBirthDate { person.nextBirthDate = nextBirthDate } }) if self.managedObjectContext.hasChanges { try self.managedObjectContext.save() } } catch { print(error) } // Set the batch size to a suitable number. fetchRequest.fetchBatchSize = 20 // Edit the sort key as appropriate. let sortDescriptors = [NSSortDescriptor(key:"nextBirthDate", ascending: true)] fetchRequest.sortDescriptors = sortDescriptors ...
如果视图控制器可以编辑
birthDate
属性 不要忘记更新nextBirthDate
属性 以及保持视图同步。
nextBirthDate
我的建议类似:
- 获取全部customers/persons
- 筛选出今天之前 3 天和之后 3 天范围内的所有生日
像下面这样使用闭包:
func fetchBirthdayList(){
// this example considers all birthdays that are like
// |---TODAY---|
// Each hyphen represents a day
let date = Date()
let timeSpan = 3
let cal = Calendar.current
nextBirthDays = self.list.filter { (customer) -> Bool in
if let birthDate = customer.birthDate {
let difference = cal.dateComponents([.day,.year], from: birthDate as! Date, to: date)
return (( (difference.day! <= timeSpan) || ((365 - difference.day!) <= timeSpan) ) && difference.day! >= 0)
}
return false
}
}
如果你想要,你可以在之后订购结果。
干杯
奥利弗