在 prepareForSegue 完成之前调用 viewDidLoad

Posted

技术标签:

【中文标题】在 prepareForSegue 完成之前调用 viewDidLoad【英文标题】:viewDidLoad called before prepareForSegue finishes 【发布时间】:2013-02-15 08:32:33 【问题描述】:

我的印象是 viewDidLoad 将在 prepareForSegue 完成后被调用。这甚至是 Hegarty 教授斯坦福课程的方式(最近是 2013 年 2 月)。

但是,今天第一次,我注意到 viewDidLoad 在 prepareForSegue 完成之前被调用。因此,我在 prepareForSegue 中设置的属性不适用于目标 viewDidLoad 方法中的目标视图控制器。

这似乎与预期的行为相反。

更新

我刚刚弄清楚发生了什么。在我的destinationViewController 中,我有一个自定义设置器,每次更新“模型”时都会重新加载tableView:

DestinationViewController    
- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray
    
        _managedObjectsArray = [managedObjectsArray copy];
        [self.tableView reloadData];
    

事实证明,由于destinationViewController 是UITableViewController 的子类...调用'self.tableView' 会强制加载视图。根据 Apple 的文档,调用视图控制器的 view 属性可以强制加载视图。 UITableViewController 的视图就是 tableView。

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html

因此,在 prepareForSegue 中,以下行强制加载 destinationViewController 的视图:

vc.managedObjectsArray = <custom method that returns an array>;

为了解决这个问题,我将destinationViewController的模型的自定义setter改为:

- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray
    
        _managedObjectsArray = [managedObjectsArray copy];
        if ([self isViewLoaded]) 
            [self.tableView reloadData];
        
    

这只会在 tableView 在屏幕上时重新加载 tableView。因此在 prepareForSegue 期间不会强制加载视图。

如果有人反对此过程,请分享您的想法。否则,我希望这可以防止某人度过一个漫长的不眠之夜。

【问题讨论】:

你怎么知道 viewDidLoad 被调用了?你能分享一些代码吗? 我怀疑prepareForSegue 实际上是(直接或间接)调用viewDidLoad 的函数。 【参考方案1】:

过去我也遇到过类似的困惑。我学到的一般经验法则是:

    prepareForSegue 在目标 VC 的 viewDidLoad 之前调用 viewDidLoad 仅在所有出口都加载后调用 不要尝试在源 VC 的 prepareForSegue 中引用任何目标 VC 的出口。

关于 prepareForSegue 的另一个教训是避免冗余处理。例如,如果您已经通过情节提要将 tableView 单元格连接到 VC,如果您尝试同时处理 tableView:didSelectRowAtIndexPath 和 prepareForSegue,您可能会遇到类似的竞争条件。可以通过使用手动 segue 或放弃在 didSelectRowAtIndexPath 处的任何处理来避免这种情况。

【讨论】:

实际上如果你访问initWithCoder:中的outlets,它在调用prepareForSegue:之前会隐式调用viewDidLoad方法。感谢@Hampde123 的评论,这对我有帮助 如果我们遵循这些规则,如何在视图控制器之间传递数据?【参考方案2】:

我想对这里发生的事情做一点解释:

在视图显示之前调用prepareForSegue

viewDidload 在第一次访问视图时被调用(视图是延迟加载的)。

可能发生的情况是您访问了prepareForSegue 中的view,从而手动触发了视图加载。

通常流程是:

    preformSegue prepareForSegue ViewController 被添加到层次结构中 viewDidLoad

但你的情况可能发生的是:

    preformSegue prepareForSegue |— 在prepareForSegue 中,您访问view |— view 被自动加载 => viewDidLoad 被调用 从performSegue返回 ViewController 被添加到层次结构中,没有viewDidLoad(已经调用)

所以是的,通常在将ViewController 添加到层次结构之前不会访问view 属性,但如果是,则可以更早地触发viewDidLoad

【讨论】:

这是有道理的,但是如果不是来自 prepareForSegue,你如何将参数传递给新视图? 还是可以的,但是访问视图前需要设置参数【参考方案3】:

感谢分享,帮我解决了问题。

在我的例子中,destinationViewController 是一个 UITabBarController 并且修改它的 viewControllers 数组触发了 viewDidLoad:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    UITabBarController *tabBarController = segue.destinationViewController;
    tabBarController.viewControllers = ...
    tabBarController.something = something;

在 viewDidLoad 我需要设置 something 属性,所以我不得不将它向上移动:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    UITabBarController *tabBarController = segue.destinationViewController;
    tabBarController.something = something;
     tabBarController.viewControllers = ...

【讨论】:

【参考方案4】:

简单的解决办法是放置

[self.tableView reloadData];

viewWillAppear:

【讨论】:

【参考方案5】:

我的动态单元格有一个类似的问题,它在选择时显示了一个模式。 prepareForSeguedidSelect:atIndexPath 之前执行。对我有帮助的是,在情节提要中,我将 segue 重新分配为从控制器开始,而不是从动态单元原型开始。我解决了比赛条件(?),一切正常!

【讨论】:

【参考方案6】:

在我的情况下,在 prepareSegue 中设置目标演示控制器的委托会导致调用 viewDidLoad。 我搬家了 segue.destination.presentationController?.delegate = self 到 prepareSegue 结束:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?)     
    // do stuff ....
    segue.destination.presentationController?.delegate = self
     

【讨论】:

以上是关于在 prepareForSegue 完成之前调用 viewDidLoad的主要内容,如果未能解决你的问题,请参考以下文章

只有在添加第三个 segue 时才在 didSelectRowAtIndexPath 之前调用 prepareForSegue

调用 prepareForSegue 而不是 ib 按钮

在 prepareForSegue 上为 Popover Segue 传递数据:iOS 5 中的奇怪行为

如何在 iOS 中的 prepareForSegue 之前执行按钮按下操作?

未从自定义 uitableviewcell 调用 prepareForSegue

prepareForSegue 未在嵌入式 segue 中调用