Ios 如何在NSFetchedResultsController中构建子部分
我正在构建一个费用跟踪器,Ios 如何在NSFetchedResultsController中构建子部分,ios,swift,cocoa-touch,core-data,Ios,Swift,Cocoa Touch,Core Data,我正在构建一个费用跟踪器,费用只能属于一个类别,但可以有多个标签s。这是我的对象图: 在我在表格视图中列出所有费用的屏幕中,我希望费用按日期分组(日期部分),然后按类别分组(或者,使用分段控件,按标记分组)。这是预期的用户界面: 我已经可以使用NSFetchedResultsController查询所有费用,按日期、然后按类别进行划分,但我无法获得(1)类别的总额和(2)其中的费用列表。我该怎么做呢?这是我当前的代码: let fetchedResultsController: NSFetc
费用
只能属于一个类别
,但可以有多个标签
s。这是我的对象图:
在我在表格视图中列出所有费用的屏幕中,我希望费用按日期分组(日期部分),然后按类别分组(或者,使用分段控件,按标记分组)。这是预期的用户界面:
我已经可以使用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
}()
让fetchedResultsController:NSFetchedResultsController={
let fetchRequest=NSFetchRequest(entityName:“费用”)
fetchRequest.resultType=.dictionaryResultType
fetchRequest.sortDescriptors=[
NSSortDescriptor(键:#键路径(Expense.sectionDate),升序:false)
]
fetchRequest.propertiesToFetch=[
#密钥路径(费用。分段日期),
#关键路径(费用类别)
]
fetchRequest.propertiesToGroupBy=[
#密钥路径(费用。分段日期),
#关键路径(费用类别)
]
让fetchedResultsController=NSFetchedResultsController(fetchRequest:fetchRequest,
managedObjectContext:Global.coreDataStack.viewContext,
sectionNameKeyPath:#keyPath(Expense.sectionDate),
缓存名称:nil)
返回获取的ResultsController
}()
A应该预先警告我从未做过这件事,但就我个人而言,我会按如下方式着手:
不要使用propertiesToGroupBy
:它会强制您使用.dictionaryResultType
,这意味着您只能通过执行单独的获取来访问底层托管对象
相反,将另一个计算属性添加到相关的NSManagedObject子类中,将sectionDate
和category.name
组合在一起。此属性将用作FRC的sectionNameKeyPath
,以便FRC在tableView中为sectionDate和category name的每个唯一组合建立一个节
添加category.name
作为FRC底层获取的另一个排序描述符。这将确保FRC获取的费用
对象的顺序正确(即,具有相同节日期和类别名称的所有费用
对象放在一起)
为每个节添加节标题视图。节的name
属性(来自FRC)将包括节日期和类别名称。在大多数情况下,您可以去掉并忽略sectionDate,只显示类别名称和相应的总数(见下文)。但是对于第一个部分,实际上是任何给定的sectionDate的第一个部分,添加一个额外的视图(到section header视图),显示sectionDate和该sectionDate的总计
确定给定的部分是否是sectionDate的第一部分有点棘手。您可以检索上一节的名称并比较节日期
要折叠/展开节,请维护一个数组,其中包含每个节的折叠/展开状态。如果节已折叠,请在tableViewnumberOfRowsInSection
datasource方法中返回0;如果扩展,请使用FRC提供的数字
对于类别总计,迭代相关部分的对象
数组(或使用合适的.reduce
实现相同的结果)
对于sectionDate总计,过滤FRC的获取对象
,以仅包括相关sectionDate
的费用
对象,然后迭代或。减少过滤的数组
如果有任何需要澄清的地方,我很乐意添加或修改。我感谢@pbasdf的回答,但我觉得在长时间不看代码之后,我很难对解决方案了如指掌
我现在要做的不是获取Expense
对象,而是为子部分本身定义了一个新实体(CategoryGroup
,我还将创建一个TagGroup
)并获取这些实体。这些实体引用了它们所包含的费用
对象,以及表示该组的类别
或标记
。这是我的(部分完成)数据模型:
我的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")
}()
让fetchedResultsController:NSFetchedResultsController={
let fetchRequest=NSFetchRequest(entityName:“CategoryGroup”)
fetchRequest.sortDescriptors=[
NSSortDescriptor(键:#键路径(CategoryGroup.sectionDate),升序:false)
]
返回NSFetchedResultsController(fetchRequest:fetchRequest,
managedObjectContext:Global.coreDataStack.viewContext,
sectionNameKeyPath:#keyPath(CategoryGroup.sectionDate),
cacheName:“cacheName”)
}()
缺点是,我现在必须编写额外的代码,以确保无论何时创建/更新/删除费用
或类别
,都能正确定义实体之间的关系,但这对我来说是一个可以接受的折衷,因为在代码中更容易理解。在该日期分组的所有项目的sectionDate
是否完全相同?@JonRose-Yes。我有一个Expense
的扩展,它设置sectionDate
无论何时datespend