更新数据异步后重绘 UITableView

Posted

技术标签:

【中文标题】更新数据异步后重绘 UITableView【英文标题】:Redraw UITableView after updating data async 【发布时间】:2010-02-23 23:19:58 【问题描述】:

我有一个 UITableview,我用数据异步加载,因此 tableview 可能会出现没有数据。 我已经厌倦了 ReloadData 方法,但表格视图一直是空的,直到我滚动表格视图,突然出现数据。 当我将表格视图加载为详细视图并在项目之间切换时,也会发生同样的事情,之前的项目数据首先出现,一旦我在表格视图中滚动,它就会显示正确的数据。 我的猜测是 ReloadData 方法工作得很好,但我需要以某种方式重绘 tableview,关于如何解决这个问题的任何建议?

/吉米

【问题讨论】:

通常 reloadData 方法会刷新 tableview 的视图。你能放你的 TableViewController 代码示例吗? 【参考方案1】:

您说您正在异步填充内容,但您是否在主线程的上下文中调用了 reloadData ? (而不是通过填充内容的线程)

Objective-C

[yourUITableView performSelectorOnMainThread:@selector(reloadData)
                                  withObject:nil 
                               waitUntilDone:NO];

斯威夫特

dispatch_async(dispatch_get_main_queue(),  self.tableView.reloadData() )

单点触控

InvokeOnMainThread(() => this.TableView.ReloadData());

【讨论】:

谢谢你解决了 =) 单点触控的解决方案是:InvokeOnMainThread(() => this.TableView.ReloadData()); @yonel 我和 JimmyEngtröm 有同样的问题,我真的希望你说的能解决这个问题,但是我仍然有这个问题。更新 UITableView 正在使用的底层数据数组后,我找不到刷新它的方法。 @MasonG.Zhwiti:在表数据源的 numberOfRowsInSections 方法中设置断点,并在 reloadData 后检查它是否进入其中。然后检查这里返回的行数,如果不为0,则调用cellForRowAtIndex。 在我看来,这是一种解决方法,当真正的问题是您可能不应该在后台线程上进行任何 UI 更新时。我添加了另一个答案,在下面进行了更多解释。 要快速执行此操作,请使用dispatch_async(dispatch_get_main_queue(), self.tableView.reloadData() )【参考方案2】:

当您的视图当前对用户可见时,Yonels 的回答是完美的(例如:用户按下填充您的 UITableView 的重新加载按钮。)

但是,如果您的数据是异步加载的,并且您的 UITableView 在更新期间不可见(例如:您将数据添加到另一个视图中的 UITableView 并且稍后通过用户输入显示 UITableView),只需覆盖UITableViewControllerviewWillAppear 方法。

- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
[self.tableView reloadData];

积极的影响是您的UITableView 仅在用户真正想要查看它时重新加载它的数据一次,而不是在添加新项目时。

【讨论】:

【参考方案3】:

我今天遇到了类似的问题(ios 7.0 中的故事板)。 我在 UIViewController 中使用表视图。加载视图时,一切正常;所有的代表都被召唤了。然而;当底层数据源(在我的例子中,数组)被修改时;可见表行没有得到更新。它们被更新了;仅当我滚动表格视图时。

什么都试过了;在主线程上调用 reloadData;在 ViewWillAppear 中调用 reload;没有任何效果。

我发现的问题;是我没有在情节提要中建立联系;对于具有引用 Outlet 的表视图。尽管设置了数据源和委托。 我不认为这可能是问题所在。因为一开始一切都很好。

希望它对某人有所帮助。我花了很长时间才发现这一点。

【讨论】:

【参考方案4】:

我猜它没有重新加载。

当您将单元格滚动到屏幕外时,然后……

tableView: cellForRowAtIndexPath:

…将被调用。所以它会被重新加载。

我猜 UITableView 变量没有经过验证。

如果你使用 UITableView 作为主视图,你可以试试这个。

[self.view reloadData];

[self.tableView reloadData];

【讨论】:

【参考方案5】:

斯威夫特 4:

DispatchQueue.main.async  self.tableView.reloadData() 

【讨论】:

【参考方案6】:

在有些天真地复制了 yonel 的解决方案并称其为好之后,我意识到调用 performSelectorOnMainThread:withObject:waitUntilDone: 可以解决症状,但不能解决问题。更大的问题是您仍在异步或后台线程的上下文中进行 UI 更新。

这就是我的代码的样子:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^

  // Make API call
  // Retrieve data, parse JSON, update local properties
  // Make a call to reload table data

);

什么时候应该是这样的:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^

  // Make API call
  // Retrieve data, parse JSON, update local properties

  dispatch_async(dispatch_get_main_queue(), ^
    // Now make the call to reload data and make any other UI updates
    [self.tableView reloadData]
  );

);

如果您需要做的唯一事情是调用[self.tableView reloadData],那么使用performSelectorOnMainThread:withObject:waitUntilDone: 可能没问题,因为它实现了相同的目标,但您也应该认识到大局中正在发生的事情。此外,如果您要做的 UI 工作不仅仅是重新加载表格,那么所有这些代码也应该放在主队列中。

参考:A concise example 使用 GCD 和管理后台与主线程。

【讨论】:

以上是关于更新数据异步后重绘 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

使用ajax刷新表格内容后重绘数据表?

在 UICollectionViewFlowLayout 使其布局无效后重绘单元格

动态更新 UITableView 部分标题

使用更新的数据重绘数据表

情节:如何用新数据更新/重绘情节表达图?

.data() 处的 D3 新数据使 svg 重绘而不是更新节点位置