2017-06-04 80 views
3

我正在构建费用跟踪器,其中Expense只能属于一个Category,但可以有多个Tag s。这是我的对象图:如何在NSFetchedResultsController中构建子部分

enter image description here

在我列出所有的费用表视图的画面,我想费用由日期(sectionDate)进行分组,然后由Category(或者,使用分段控制,通过Tag)。这是预期的UI:

enter image description here

我已经可以做出NSFetchedResultsController查询所有费用,按日期节他们,然后按类别搜索,但我不能得到(1)类别和总( 2)其中的费用清单。我该如何着手做这件事?这是我当前的代码:

let fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult> = { 
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Expense") 
    fetchRequest.resultType = .dictionaryResultType 

    fetchRequest.sortDescriptors = [ 
     NSSortDescriptor(key: #keyPath(Expense.sectionDate), ascending: false) 
    ] 

    fetchRequest.propertiesToFetch = [ 
     #keyPath(Expense.sectionDate), 
     #keyPath(Expense.category) 
    ] 
    fetchRequest.propertiesToGroupBy = [ 
     #keyPath(Expense.sectionDate), 
     #keyPath(Expense.category) 
    ] 

    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, 
                   managedObjectContext: Global.coreDataStack.viewContext, 
                   sectionNameKeyPath: #keyPath(Expense.sectionDate), 
                   cacheName: nil) 
    return fetchedResultsController 
}() 
+0

是'sectionDate'完全相同的所有项目在该日期组? –

+0

@JonRose是的。我有'Expense'的扩展名,每当'dateSpent'被修改时它会设置'sectionDate'。 'sectionDate'是只有MM/DD/YY组件的'dateSpent'。 'sectionDate'本身也存储在核心数据中 - 它不是一个瞬态属性。 –

回答

0

我很欣赏@ pbasdf的回答,但是我觉得在经过很长一段时间没有看代码之后,我会很难把头埋在解决方案中。

我是来干什么的周围,而不是获取Expense对象,我定义的小节自己一个新的实体(CategoryGroup,我也会让TagGroup),并获取这些实体代替。这些实体引用了它们包含的Expense对象,以及代表该组的CategoryTag。这是我的(部分完成)的数据模型:

enter image description here

而且我NSFetchedResultsController现在在代码简单得多:

let fetchedResultsController: NSFetchedResultsController<CategoryGroup> = { 
    let fetchRequest = NSFetchRequest<CategoryGroup>(entityName: "CategoryGroup") 
    fetchRequest.sortDescriptors = [ 
     NSSortDescriptor(key: #keyPath(CategoryGroup.sectionDate), ascending: false) 
    ] 
    return NSFetchedResultsController(fetchRequest: fetchRequest, 
             managedObjectContext: Global.coreDataStack.viewContext, 
             sectionNameKeyPath: #keyPath(CategoryGroup.sectionDate), 
             cacheName: "CacheName") 
}() 

的缺点是,我现在必须编写额外的代码,使绝对确保在创建/更新/删除ExpenseCategory时正确定义实体之间的关系,但对我来说这是一个可接受的折衷方案,因为它更易于在代码中理解。

1

A应该预先警告,我从来没有这样做,但我个人会设置一下就可以如下:

  1. 不要使用propertiesToGroupBy:它迫使你使用.dictionaryResultType这意味着您只能通过执行单独的提取访问底层的托管对象。
  2. 相反,将其他计算属性添加到相关的NSManagedObject子类中,合并sectionDatecategory.name。此属性将用作FRC的sectionNameKeyPath,以便FRC将为tableDate和类别名称的每个唯一组合在tableView中建立一个部分。
  3. category.name添加为FRC底层的另一个排序描述符。这将确保FRC提取的Expense对象的顺序正确(即所有具有相同节日日期和类别名称的Expense对象在一起)。
  4. 为每个部分添加节标题视图。部分(来自FRC)的name属性将包含sectionDate和类别名称。在大多数情况下,您可以删除并忽略sectionDate,只显示类别名称和相应的总数(见下文)。但是对于第一部分以及任何给定部分日期的第一部分,添加一个额外的视图(部分标题视图),显示sectionDate的sectionDate和总计。
  5. 判断一个给定的部分是否是sectionDate的第一部分有点棘手。您可以检索上一节的名称并比较sectionDates。
  6. 要折叠/展开节,请维护一个数组来保存每个节的折叠/展开状态。如果该部分已折叠,请在tableView numberOfRowsInSection数据源方法中返回0;如果扩大使用FRC提供的数字。
  7. 对于类别总数,遍历相关部分的objects数组(或使用合适的.reduce实现相同)。
  8. 对于sectionDate合计,筛选fetchedObjects以使FRC仅包含相关sectionDateExpense对象,然后迭代或.reduce已过滤的数组。

如果有任何需要澄清,我很乐意补充或修改。

相关问题