2016-04-15 44 views
2

我使用Xcode 7.3和Swift 2.2以及NSFetchedResultsController。是否可以创建配置谓词和排序描述符来解决此问题所需的提取请求?使用CoreData如何配置获取请求以查找即将到来的生日?

鉴于Person具有birthDate属性的实体如何配置获取请求以返回即将到来的生日?这是我曾尝试:

  1. 我创建了一个名为birthDateThisYear瞬态属性和配置,今年返回的人的生日。但是我发现,您不能在Core Data的提取请求中使用transient属性。

  2. 我用birthDateDayNumberbirthDateMonthNumber属性与birthDate一个定制的setter沿着非规范化试图接受的答案here但我无法弄清楚谓语。如果今天是12月31日呢?不知何故,它将需要包装1月,2月和3月

  3. 我读到它可以完成表达式和比较谓词。但我找不出解决方案。任何人都有这个工作?

  4. 我认为它的工作原理是创建一个称为birthDateInYear2000的非规范化属性,但同样也会遇到同样的重叠问题。

任何想法?

回答

4

建议:

  • 所有生日。
  • 从现在

    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包含升序排列所有即将到来的生日。

在核心数据,你可以提取记录作为生日而objectid(或全名)的字典,创建一个临时的结构,地图和项目进行排序,并得到了的objectID的人(或使用全名) - 或者你甚至可以将逻辑应用到NSManagedObject阵列

编辑

使用一个NSFetchedResultsController如果对下一个生日的信息存储在坚持,你可以排序表视图只(假设它是MySQL存储),因为您不能应用排序描述符,包括指向瞬态属性或计算属性的键。

更新nextBirthDate属性的最佳位置就在创建视图控制器的NSFetchedResultsController实例之前。

  • 在实体创建(可选的)属性nextBirthDatePerson
  • 创建扩展的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属性以保持视图同步。

+0

看起来有前途的!我忽略了说我正在使用'NSFetchedResultsController'。你认为你的答案可以适应吗?它似乎并不如此。它需要交给配置好的'NSFetchRequest'。 –

+0

我更新了答案建议用'NSFetchedResultsController'的解决方案。唯一的缺点是'nextBirthDate'属性必须是持久的。 – vadian

+0

好思想!我会试试看。这对于大型数据集可能不太适用,但是这个应用程序的Person实体数量很少。可能不超过25次。 –

0

我的建议是相似的:

  • 获取所有客户/人
  • 过滤器,前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 
    } 
} 

如果你愿意,你可以在之后订购结果。

干杯

奥利弗