【问题标题】:How can I reload items without removing and inserting with UITableViewDiffableDataSource?如何在不使用 UITableViewDiffableDataSource 删除和插入的情况下重新加载项目?
【发布时间】:2020-06-22 13:03:48
【问题描述】:

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

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

我这样声明数据源:

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

SearchHit代表一个搜索结果;它具有显示标题的属性和要在标题中突出显示的范围数组。它会覆盖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 调用有所帮助,但现在大多数单元格都在不断更新。这听起来像是我的代码中某处的逻辑错误,但我已经验证传递给快照的命中是正确的,而传递给数据源的单元格创建回调的命中不是。

This article by Donny Wals 和this related Twitter thread 涉及 Steve Breen 建议解决此问题的方法是使项目标识符类型仅表示显示单元格所需的属性。所以我更新了SearchHit 的哈希和相等比较,以包括标题的突出显示部分,这是他们以前没有的。然后我在每次更新时为所有单元格删除和插入动画,这是我不想要的。

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

GitHub 上的示例项目here

【问题讨论】:

  • ...animatingDifferences: NO] 怎么样?
  • @vadian 很有趣,它解决了背后的问题。但是动画是使用 diffable 数据源的重点。也许这值得一试。
  • animatingDifferences 参数似乎表明动画不是整个点 ????
  • @vadian 好的,公平的:-)。但是动画差异是我在旧的[self.tableView reloadData] 上使用这个 API 的主要原因。如果我从引入它的 WWDC 谈话中没记错的话,animatingDifferences 参数的存在至少部分是为了避免在加载视图时为数据的初始外观设置动画,以及其他此类边缘情况?
  • 我已将其归档为 FB7621476。

标签: objective-c uitableview diffabledatasource nsdiffabledatasourcesnapshot


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    diffable 数据源 API 可能不是对单元格本身产生动画效果的正确工具。它适用于细胞出现、消失和排序的动画。如果您的数据源有通过 Hashable 一致性表示的更改,则 api 会将其视为更改并删除/插入等。

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

    【讨论】:

    • 我不需要单元格本身的动画,真的 - 我只需要在没有删除/插入动画的情况下更新显示。这不是reloadItemsWithIdentifiers 的用途吗?我在 GitHub 上添加了示例代码来说明。
    • @TomHamming 你最后做了什么?
    • @SherwinZadeh 我在 WWDC 实验室与一位 Apple 工程师讨论过这个问题,他们似乎认为这是一个错误 - reloadItemsWithIdentifiers 应该处理这个问题。在它得到修复之前,我只是不制作动画。
    • @TomHamming 你好,我现在遇到了同样的问题,谢谢你提供这么有用的信息,你是真正的救星
    • 这个问题还没有解决办法吗?在我看来,这是一个必须以某种方式工作的基本功能?
    猜你喜欢
    • 1970-01-01
    • 2011-01-19
    • 2012-11-27
    • 2021-08-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    相关资源
    最近更新 更多