【问题标题】:Animate view controller and reload data in table view at the same time动画视图控制器并同时在表格视图中重新加载数据
【发布时间】:2015-02-13 10:29:02
【问题描述】:

我有一个根视图控制器,它以标准动画呈现模态视图控制器(模态视图控制器从下到上出现)。

让我们将此视图控制器命名为 MyRootViewController 和 MyModalTableViewController。

问题是如果MyModalTableViewController在出现时重新加载数据,动画就会停止。

例如:

- (void)openModalViewController {
  MyModalTableViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:@"myModalScreen"];
  [self presentViewController:vc animated:YES];
}

在MyModalTableViewController 我有下一个代码:

- (void)viewDidLoad {
  self.itemList = [[MyData sharedInstance] itemList]; // self.itemList is NSArray
}

// ...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  MyTableViewCell * cell = [tableView dequeReusableCellWithIdentifier:@"myCell"];
  cell.item = self.itemList[indexPath.row];
  return cell;
}

所以当MyModalTableViewController 从情节提要加载时,它会加载itemList 并在UITableView 上显示它。只有当UITableView 完成加载数据时,演示动画才会开始。我猜是因为动画和数据重新加载在同一个线程中工作。因此,如果我要显示 10000 个项目,则需要几秒钟,然后才会开始演示动画。

太慢了。所以我的问题是解决这个问题的最佳方法是什么?

【问题讨论】:

  • 为什么不反其道而行之?首先是动画(可能带有活动指示器),然后是 reloadData。

标签: ios objective-c uitableview uianimation presentviewcontroller


【解决方案1】:

嗯,你可以在后台线程中加载你的项目列表

- (void)viewDidLoad {

    //background thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        //load data
        self.itemList = [[MyData sharedInstance] itemList]; // self.itemList is NSArray

        //main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            //reload table
            [self.tableView reloadData];
        });

    });

}

【讨论】:

  • 是的,你是对的,但它不能解决问题,因为[self.tableView reloadData] 将在动画进行时启动:)
【解决方案2】:

在MyModalTableViewController中,添加一个方法loadData

- (void)loadData {
     self.itemList = [[MyData sharedInstance] itemList]; // self.itemList is NSArray
     [self.tableView reloadData];
 }

然后使用`presentViewController的完成块

 [self presentViewController:vc animated:YES completion:^{
    [vc loadData];
}

【讨论】:

  • 感谢您的回复。我已经考虑过这一点,但我想还有更优雅的解决方案。
  • 另外,如果我先将MyModalTableViewController 推送到UINavigationController,代码会更复杂且不可重用。所以,我将不得不通过导航控制器访问必要的屏幕。
  • 那么viewDidAppear 呢?此方法在动画完成时调用,因此您将获得相同的结果并与导航堆栈兼容。为确保您的代码不会被多次调用(viewDidAppear 在子视图控制器被解除时也会被调用),请使用中间属性来了解它是否是第一个 init。
  • 再次感谢您尝试帮助我。问题不在我预期的地方,它有点深。我已经找到答案了,我稍后会发布。
  • 我很期待看到它;)
【解决方案3】:

由于我试图从 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 委托方法呈现视图控制器而导致的问题。

这个委托方法不在主线程中调用,这就是动画运行缓慢的原因。它看起来太奇怪了,因为在 iOS 7 中我没有这样的问题。它仅在 iOS 8 及更高版本上发生。

我在这个 SO 主题中发现了同样的问题:Slow presentViewController performance

所以解决方案是实现如下委托:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  __block UIViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:@"myVC"];
  dispatch_async(dispatch_get_main_queue(), ^{
    [self presentViewController:vc animated:YES completion:nil];
  });
}

我查看了 Apple 文档,但没有发现此委托方法调用不在主线程中的通知:https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/index.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:didSelectRowAtIndexPath:

如果有人解释为什么这个问题只在 iOS 8 及更高版本上引起,那就太好了。

【讨论】:

  • 嗨,我现在才看到你的回答,你猜怎么着:几个月前我也遇到了同样的问题!实际上,我正在使用 iOS 8 SDK 在 Swift 中重新编写一个 objC 应用程序,当我尝试从 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 推送一个 viewController 时,动画真的很慢。我认为这是一个 Swift 问题,但多亏了你,我现在知道这是一个 iOS 8 问题。很奇怪,它没有在任何地方提及。
【解决方案4】:

可以在之前的视图控制器中对itemlist进行收费,并设置为新的:

- (void)openModalViewController {
  MyModalTableViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:@"myModalScreen"];
  vc.itemlist = self.itemlist;
  [self presentViewController:vc animated:YES];
}

【讨论】:

    猜你喜欢
    • 2011-02-05
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    相关资源
    最近更新 更多