29

我的印象是 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 模型的自定义设置器更改为:

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

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

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

4

6 回答 6

25

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

  1. 在目标 VC 的 viewDidLoad 之前调用 prepareForSegue
  2. viewDidLoad 仅在加载所有插座后调用
  3. 不要试图在源 VC 的 prepareForSegue 中引用任何目标 VC 的出口。

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

于 2013-08-07T15:57:21.563 回答
3

想我会在这里发生的事情添加一点解释:

prepareForSegue在视图显示之前调用

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

可能发生的情况是您访问了view手动prepareForSegue触发视图加载的方法。

通常流程是:

  1. preformSegue
  2. prepareForSegue
  3. ViewController被添加到层次结构中
  4. viewDidLoad.

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

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

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

于 2017-05-26T03:40:57.243 回答
2

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

在我的例子中,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 = ...
}
于 2013-05-28T12:37:09.603 回答
1

简单的解决方案是放置

[self.tableView reloadData];

viewWillAppear

于 2014-08-17T02:24:57.387 回答
0

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

于 2019-11-20T09:52:35.903 回答
0

在我的情况下,在 prepareSegue 中设置目标演示控制器的委托会导致调用 viewDidLoad。我将 segue.destination.presentationController?.delegate = self 移动到 prepareSegue 的末尾:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?)     {
    // do stuff ....
    segue.destination.presentationController?.delegate = self
     }
于 2021-06-07T14:03:47.400 回答