ios - 使用 CoreData 如何配置获取请求来查找即将到来的生日?

标签 ios swift core-data nspredicate nsfetchrequest

我使用 Xcode 7.3 和 Swift 2.2 以及 NSFetchedResultsController。是否可以创建配置有谓词和排序描述符的所需获取请求来解决此问题?

给定一个具有 birthDate 属性的 Person 实体,如何配置提取请求以返回即将到来的生日?这是我尝试过的:

  1. 我创建了一个名为 birthDateThisYear 的 transient 属性,并将其配置为返回此人今年的生日。但我发现你不能在 Core Data 的获取请求中使用 transient 属性。

  2. 我尝试了接受的答案 here通过使用 birthDateDayNumberbirthDateMonthNumber 属性以及 birthDate 的自定义 setter 进行非规范化,但我无法弄清楚谓词。如果今天是 12 月 31 日怎么办?不知何故,它需要包含一月、二月和三月。

  3. 我读到它可以通过表达式和比较谓词来完成。但我想不出解决办法。有人成功了吗?

  4. 我认为创建一个名为 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 { $0.compare($1) == .OrderedAscending }
    
  • 现在 sortedNextBirthDays 包含所有即将到来的生日,按升序排序。

在 Core Data 中,您可以以包含生日和 objectID(或全名)的字典形式获取记录,创建临时结构,对项目进行映射和排序,并获取 objectID 的人员(或使用全名) - 或者您甚至可以将逻辑应用于 NSManagedObject 数组

编辑

使用NSFetchedResultsController如果有关下一个生日的信息存储在持久存储中(假设它是 MySQL 存储),则可以对 TableView 进行排序,因为您无法应用排序描述符,包括指向 transient 或计算属性的键。

更新 nextBirthDate 属性的最佳位置是在创建 View Controller 的 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
       ...
    
  • 如果 View Controller 可以编辑 birthDate 属性,请不要忘记更新 nextBirthDate 属性以保持 View 同步。

关于ios - 使用 CoreData 如何配置获取请求来查找即将到来的生日?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36637896/

相关文章:

ios - Split View Controller 必须是 Root View Controller

iOS: block 内的 UIBackgroundFetchResult 完成处理程序

ios - 论View和ViewController的职责和沟通

ios - 如何在IOS中实现firebaseUI

swift - ViewController 中的 TableView 而不是 Datan| 的 TableViewController解析网

core-data - 尝试使用 NSFetchedResultsController 创建 USE_BLOCK_IN_FRAME ... EXC_BAD_ACCESS

ios - 核心数据+组合架构

ios - Swift:当didSelectRowAtIndexPath时如何更新Core Data中的数据?

ios - 如何为我的 iOS 导航栏创建水平渐变背景?

ios - 数字到 firebase 迁移 iOS 电话号码输入