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

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

/吉米

【问题讨论】:

  • 通常 reloadData 方法会刷新 tableview 的视图。你能放你的 TableViewController 代码示例吗?

标签: iphone uitableview xamarin.ios


【解决方案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 和管理后台与主线程。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-04-16
            • 1970-01-01
            • 2012-08-27
            • 1970-01-01
            • 2017-03-07
            • 2015-11-24
            相关资源
            最近更新 更多