当导航返回时重新加载UITableView?

59
我有一个最高级别的UIViewController,其中包含一个UITableView。最高级别的UIViewController实例化了一个NavigationController,并将另一个UIViewController推入NavigationController。也就是说,我们进入了一个新的第二个视图。这个第二个视图有通常在左上角的“返回”按钮,以便您可以导航回到顶级视图。

当从第二个视图导航回顶级视图时,是否可能使用在第二个视图中生成的数据重新绘制顶级视图中的UITableView,通过在顶级中调用cellForRowAtIndexPath,如果可以,如何做到这一点?

7个回答

115

你只需要在拥有UITableView的UIViewController中添加以下代码,此时你无需担心单元格级别发生的事情。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.tableView reloadData]; // to reload selected cell
}

只需将上述代码添加到您的控制器中,当您从第二个视图返回时,您会发现正确的事情发生了。调用reloadData告诉表视图需要从您的模型刷新其单元格,其他所有内容都会很好地跟随。


1
我使用了这种方法,但是不得不将代码从我的didViewLoad移动到viewWillAppear中,因为它们都在初始加载时触发。对我来说,这是一个更大的问题,因为我需要从Web服务下载新的项目详细信息。 - PowerMan2015

14
如果你只想重新加载被选中的单元格,那么请在UITableViewController的自定义子类中覆盖viewWillAppear:方法,例如:
- (void)viewWillAppear:(BOOL)animated
{
    NSIndexPath *selectedRowIndexPath = [self.tableView indexPathForSelectedRow];
    [super viewWillAppear:animated]; // clears selection
    if (selectedRowIndexPath) {
        [self.tableView reloadRowsAtIndexPaths:@[selectedRowIndexPath] withRowAnimation:UITableViewRowAnimationNone];
    }
}

注意:假设您将 clearsSelectionOnViewWillAppear 设置为 YES(默认值),在调用 super 之前,必须获取所选行的索引路径,以清除选择。

另外,@ZoranSimic 的解决方案 只需调用 [self.tablView reloadData],也是可接受的,因为它代码更少且效率仍然高。

最后,保持表视图单元格与其表示的模型对象同步的最佳方法可能是像使用键值观察(KVO)和/或 NSNotification 一样,像 NSFetchedResultsController 那样。当模型对象发生更改时,通知您的表视图控制器,以便它可以重新加载相应的单元格。表视图控制器可以在 viewDidLoad 中开始观察其模型对象的更改,并在 dealloc(以及您 手动卸载 self.view 的任何地方)中结束观察。


9
除了 Zoran Simic 在此处的答案之外,以下是 Swift 代码:
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    tableView.reloadData()
}

1
在从viewWillAppear()重新加载数据时,请注意不要从viewDidLoad()获取数据。 - Changnam Hong
警告:UITableView 被告知在不在视图层次结构中的情况下布局其可见单元格和其他内容(表视图或其任一父视图尚未添加到窗口中)。这可能会导致错误,因为它强制表视图内部的视图加载并执行布局,而没有准确的信息(例如表视图边界、特征集合、布局边距、安全区域插入等),也会因额外的布局传递导致不必要的性能开销。 - Cloud

5
您可以实现方法,并创建逻辑以在弹出视图控制器时进行刷新。
另一种方法是在您的表视图控制器上实现的一些逻辑,以根据弹出的视图控制器的数据进行刷新。
如果您需要从第二个视图控制器发送数据到第一个视图控制器,请记住您的第二个视图控制器“不知道”之前的视图控制器的存在。它应该对此透明。您应该实现一些协议,使第二个视图控制器向第一个视图控制器发送数据。这将是解决此问题的第三个选项,因为您的第一个视图控制器将是委托,并且第二个视图控制器将向委托发送信息,您可以根据接收到的数据准备您的表视图(第一个视图控制器)重新加载。

3

viewWillAppear方法会在每次视图出现时调用,包括第一次。 以下是我提供的解决方案,仅在导航返回时重新加载视图。

我在ViewController.h文件中创建了一个变量,用于检查是第一次进入此ViewController还是导航返回。

@property (nonatomic) BOOL isViewExist;

viewWillAppear方法中,之后...
-(void)viewWillAppear:(BOOL)animated{
    if(!self.isViewExist){
        self.isViewExist = YES; // check it is the first time you go to this ViewController -> don't reload anything
    }else{
        [self.tableView reloadData]; // to reload the tableview data
        // or your can refresh anything in your ViewController as you want
    }
}

希望这可以帮到您。

1

也许现在可以帮忙。

对于 Swift 2+

在你的 viewDidAppear 方法中:

如果你想重新加载整个表格:

tableView.reloadData()

如果您想重新加载仅选定的单元格。

let index = tableView.indexPathForSelectedRow
if (index != nil){
  self.tableView.reloadRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimation.Automatic)
}

0

已更新至Swift 3

let index = tableView.indexPathForSelectedRow
    if (index != nil){
        self.tableView.reloadRows(at: [index!], with: UITableViewRowAnimation.automatic)
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接