从关系中观察到 sectionNameKeyPath 的变化
Posted
技术标签:
【中文标题】从关系中观察到 sectionNameKeyPath 的变化【英文标题】:Observe to sectionNameKeyPath changes when from relationship 【发布时间】:2017-08-13 00:53:01 【问题描述】:确保sectionKeyPathName
值(来自相关实体)的更改传播到 UITableView 的部分标题的最佳做法是什么(包括使用新值重新绘制部分标题并在需要时更改部分排序) ?
我假设 NSFetchedResultsController 委托的当前功能无法满足我的需求,因为
NSFetchedResultsController
正在观察一个实体(Recipe 在我的情况下是针对表格行)而不是 sectionKeyPathName
的实体(类别 的名称我的财产。)
NSFetchedResultsController
委托的 controller(_:didChange:atSectionIndex:for)
永远不会为其类型参数返回 move 或 update
背景
我有两个实体,Category 和 Recipe,其中一个 Category 可以有多个 Recipes,而一个 Recipe 将只属于 1 个类别(又名 1:M 关系)。
我有一个食谱的表格视图,每个类别都有一个部分。部分标题是类别的名称。我使用了 fetchedResultsController 来填充表格视图。一切都按预期工作(即,当食谱更新、添加、删除或更改其类别时,表格视图会反映这些更改),但有一个例外。当类别名称更改时,我无法更改部分标题。我不仅希望标题反映更改的名称,还希望根据需要重新排序。
代码片段
我会根据需要分享。正如我所说,其他一切都正常,并且有很多代码。
FWIW - 我的 sectionKeyPathName
值与 sortDescriptor 数组的第一个值相同。
尝试失败
我假设我需要观察类别的name
属性以进行更改。最坏的情况是,我的部分需要重新排序。因此,如果name
更改了,我将再次performFetch()
,然后将reloadData()
放在桌子上。我试过这种技术。
-
观察
NSManagedObjectContextWillSave
以确定类别(当前是我的表格视图中的一个部分)的name
属性是否发生变化。
如果name
属性发生变化,那么当我观察到NSManagedObjectContextDidSave
时,我将再次执行提取并重新加载数据()。这似乎解决了问题,但是当我测试将食谱移动到不同的类别时崩溃了。 (移动测试在此更改之前有效。)(崩溃为 An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of sections.
)
【问题讨论】:
【参考方案1】:fetchedResultsController 很棒。但他们并不是超级聪明。他们仅监控设置为获取的实体的更改。它假定所有其他更改都不会影响它。所以如果你有一个基于关系的谓词或排序描述符,它可能会导致问题。
可能的解决方案:
1) 列出类别而不是食谱
尽管 fetchedResultsController 被设计为在 1:1 设置中与 tableview 或 collectionView 很好地工作(即 fetchedResultsController 的 indexPath 等于视图的 indexPath),但它不需要那样工作。
您可以为没有 sectionKeyPathName 的类别创建一个 fetchedResultsController。然后将节数设置为控制器中的项目数。每个部分中的项目数等于每个类别中的食谱数。
如果您有一个谓词来过滤食谱,这可能会变得更加困难。
2) 有变化时触发fetchedResultsController
如果您只在少数几个地方更改类别,则可能很容易简单地“弄脏”该类别中的所有配方以触发 fetchedResultsController。如果您将属性设置为等于自身(即 r.recipeId = r.recipeId),它将触发 fetchedResultsController 中的更新。因此,当您更改 categoryName 时,还会遍历所有食谱并将它们弄脏。
3) 有两个 fetchedResultsController
FetchedResultsController 是非常轻量级的对象,您不必害怕根据需要制作任意数量的对象。您可以创建两个。一份用于食谱,一份用于类别。这些部分基于 fetchedResultsController 类别。对于配方 fetchedResultsController,您可以根据类别的不变属性(例如 categoryId)对其进行分组。然后,当您想知道某个类别的 numberOfRows 时,您必须在配方 fetchedResultsController 中找到它。弄清楚 indexPath 可能有点烦人 - 但如果你创建一个单独的对象来管理它,这没什么大不了的。
如果您要显示所有食谱,我会推荐 #1。如果你对你的食谱有一个谓词,我会推荐#2。如果您是代码纯粹主义者并且希望完全分离模型和视图,我只会推荐#3。
【讨论】:
感谢您提供的解决方案选项。 列出类别似乎是在用一个问题换另一个问题。每当配方名称更改时,此解决方案是否会导致难以更新表?我正在尝试实现 Option 2,因为我已经有了跟踪类别名称更改的代码 - 这将是我可以触发 dirty-ing 函数的时候。需要明确的是,您认为我在任何时候都不需要在我的 resultsController 上再次performFetch()
吗?
无需多次调用 performFetch。 fetchedResultsController 应该跟踪更改。以上是关于从关系中观察到 sectionNameKeyPath 的变化的主要内容,如果未能解决你的问题,请参考以下文章