如何在不使用UITableViewDiffableDataSource移除和插入的情况下重新加载项



我正在使用UITableViewDiffableDataSource在应用程序中实现搜索屏幕。每个单元格表示一个搜索命中,并在单元格标题中突出显示搜索匹配项,有点像Xcode的"快速打开"窗口突出显示其结果项的部分。在搜索字段中键入文本后,我会更新结果列表。结果在列表中随着相关性的变化而上下移动。

诀窍是,每次搜索文本更改时,我都需要强制每个单元格重新呈现,因为新的搜索字符串意味着更新单元格标题的突出显示部分。但我不想设置删除和插入的动画,因为它仍然是同一个项目。如何使用快照告诉数据源需要重新加载单元格?

我这样声明数据源:

@property (retain) UITableViewDiffableDataSource<NSString *, SearchHit *> *dataSource;

CCD_ 2表示一个搜索结果;它具有显示标题的属性和要在标题中突出显示的范围数组。并且它覆盖hashisEqual:,使得每个结果行都是唯一标识的。

我的代码看起来像这样:

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSArray<SearchHit *> *hits = [self fetchHits:searchText];
NSDiffableDataSourceSnapshot<NSString *, SearchHit *> *snap = [[[NSDiffableDataSourceSnapshot alloc] init] autorelease];
[snap appendSectionsWithIdentifiers:@[@""]];
[snap appendItemsWithIdentifiers:hits];
[snap reloadItemsWithIdentifiers:hits];
[self.dataSource applySnapshot:snap animatingDifferences:YES];
}

一开始我在那里没有reloadItemsWithIdentifiers调用,然后一旦它出现在结果列表中,任何单元格都不会改变。添加reload调用有所帮助,但现在大多数单元格总是落后一个更新。这听起来像是我代码中的某个逻辑错误,但我已经验证了传递给快照的命中率是正确的,而传递给数据源的单元格创建回调的命中率不是。

Donny Wals的这篇文章和Steve Breen的相关推特帖子建议,解决这个问题的方法是使项目标识符类型仅表示显示单元格所需的属性。因此,我更新了SearchHit的hash和equality比较,以包括标题中突出显示的部分,而他们以前没有这样做。然后我在每次更新时都删除并插入了所有单元格的动画,这是我不想要的。

这似乎是reloadItemsWithIdentifiers应该做的…对吧?

GitHub上的示例项目。

可区分数据源API可能不是在单元本身上实现动画的正确工具。它适用于细胞的出现、消失和排序的动画。如果你的数据源有一个通过Hashable一致性表达的更改,api会将其视为更改并删除/插入等。

我的建议是从项目标识符中删除搜索文本,让每个单元格观察搜索文本,并独立于数据源进行动画或重新绘制。

正确的解决方案实际上是在API的名称中——您提供给数据源的对象应该是标识符,就像数据库中的rowid值一样。在我的情况下,当项目标识符不代表我可以查找的数据库中的行时,我只需要将对象的状态保持在某种查找结构中,这样当我调用reloadItemsWithIdentifiers时,我就可以从该结构中获得每个单元格的状态,而不是从数据源交给我的对象中获得。

相关内容

最新更新