从关系时观察sectionNameKeyPath更改

时间:2017-08-13 00:53:01

标签: ios swift uitableview core-data nsfetchedresultscontroller

确保将sectionKeyPathName值(来自相关实体)的更改传播到UITableView的节标题的最佳做法是什么(包括使用新值重新绘制节标题并更改节顺序,如果需要的话)?

我假设NSFetchedResultsController委托的当前功能无法满足我的需求,因为

  1. NSFetchedResultsController正在观察一个实体(在我的情况下, Recipe 表行)而不是sectionKeyPathName的实体(类别我的名字属性。)
  2. NSFetchedResultsController代表的controller(_:didChange:atSectionIndex:for)永远不会为其类型参数返回移动更新
  3. 背景

    我有两个实体,分类和食谱,其中一个类别可以有多个食谱,一个食谱只属于一个类别(又名1:M关系。)

    我有食谱的表格视图,每个类别都有一个部分。节标题是类别的名称。我使用了fetchedResultsController来填充表视图。一切都按预期工作(即,当食谱被更新,添加,删除或更改其类别,表视图反映这些更改)与一个例外。当类别名称更改时,我无法更改节标题。我不仅希望标题反映更改的名称,还要根据需要重新排序。

    代码段

    我会根据需要分享。正如我所说,其他一切都有效,并且有很多代码。

    FWIW - 我的sectionKeyPathName值与sortDescriptor数组的第一个值相同。

    尝试失败

    我假设我需要观察类别的name属性进行更改。最糟糕的情况是,我的部分需要重新订购。因此,如果name发生了变化,我会再次performFetch(),然后再reloadData()。我试过这种技术。

    1. 观察NSManagedObjectContextWillSave以确定某个类别(当前是我的表格视图中的某个部分)是否更改了name属性。
    2. 如果name属性发生了变化,那么当我观察NSManagedObjectContextDidSave时,我会再次执行fetch和reloadData()。这似乎解决了这个问题但是当我测试将配方移动到另一个类别时崩溃了。 (移动测试在此更改之前有效。)(崩溃为An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of sections.

1 个答案:

答案 0 :(得分:0)

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。