我正在构建费用跟踪器,其中Expense
只能属于一个Category
,但可以有多个Tag
。这是我的对象图:
在我列出表格视图中所有费用的屏幕中,我希望按日期(sectionDate
),然后按Category
(或使用分段控件)对费用进行分组,Tag
)。这是预期的用户界面:
我已经可以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 :(得分:1)
A应该预先知道我从未这样做过,但我个人会按照以下方式进行讨论:
propertiesToGroupBy
:它会强制您使用.dictionaryResultType
,这意味着您只能通过执行单独的提取来访问基础托管对象。sectionDate
和category.name
组合在一起。此属性将用作FRC的sectionNameKeyPath
,以便FRC将在tableView中为sectionDate和类别名称的每个唯一组合建立一个部分。category.name
作为FRC底层提取的另一个排序描述符。这将确保FRC获取的Expense
个对象的顺序正确(即具有相同sectionDate和类别名称的所有Expense
个对象在一起)。name
属性(来自FRC)将包括sectionDate和类别名称。在大多数情况下,您可以去掉并忽略sectionDate,只显示类别名称和相应的总数(见下文)。但是对于第一部分,实际上是任何给定sectionDate的第一部分,添加一个额外的视图(到部分标题视图),显示该部分日期的sectionDate和总计。numberOfRowsInSection
数据源方法中返回0;如果扩展使用FRC提供的数字。objects
数组(或使用合适的.reduce
来实现相同的目标)。fetchedObjects
以仅包含相关Expense
的{{1}}个对象,然后迭代或.reduce过滤后的数组。如果有任何需要澄清,我很乐意添加或修改。
答案 1 :(得分:0)
我很欣赏@pbasdf的答案,但我觉得在经过很长一段时间不查看代码后,我将很难绕过解决方案。
我接下来要做的不是获取Expense
个对象,而是为子节本身定义了一个新实体(CategoryGroup
,我还会创建一个TagGroup
)并改为获取这些实体。这些实体引用了它们包含的Expense
个对象,以及代表该组的Category
或Tag
。这是我的(部分完整的)数据模型:
我的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")
}()
缺点是我现在必须编写额外的代码以确保在创建/更新/删除Expense
或Category
时正确定义实体之间的关系,但这是对我来说是可接受的权衡,因为在代码中更容易理解。