web-dev-qa-db-ja.com

prepareForSegueが終了する前に呼び出されたviewDidLoad

私は、prepareForSegueが終了した後にviewDidLoadが呼び出されるという印象を受けました。これは、ヘガーティがスタンフォードのクラスを教える方法でもあります(最近では2013年2月)。

しかし、今日初めて、prepareForSegueが終了する前にviewDidLoadが呼び出されたことに気づきました。したがって、prepareForSegueで設定していたプロパティは、destinationviewDidLoadメソッド内のdestinationViewControllerでは使用できませんでした。

これは予想される動作に反しているようです。

[〜#〜]更新[〜#〜]

何が起こっているのか理解しました。私のdestinationViewControllerには、「モデル」が更新されるたびにtableViewをリロードするカスタムセッターがありました。

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

DestinationViewControllerはUITableViewControllerのサブクラスであるため、「self.tableView」を呼び出すと、ビューが強制的に読み込まれます。 Appleのドキュメントによると、View Controllerの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中にビューを強制的にロードすることはありません。

このプロセスに反対する人がいたら、あなたの考えを共有してください。そうでなければ、これが誰かの長い眠れない夜を防ぐことを願っています。

28
Michael Guren

私は過去に同様の混乱に遭遇しました。私が学んだ一般的な経験則は次のとおりです。

  1. prepareForSegueは、宛先VCのviewDidLoadの前に呼び出されます
  2. viewDidLoadは、すべてのアウトレットがロードされた後にのみ呼び出されます
  3. ソースVCのprepareForSegueで宛先VCのアウトレットを参照しようとしないでください。

PrepareForSegueに関して学んだもう1つの教訓は、冗長な処理を回避することです。たとえば、すでにtableViewセルをストーリーボードを介してVCにセグエしている場合、tableView:didSelectRowAtIndexPathとprepareForSegueの両方を処理しようとすると、同様の競合状態が発生する可能性があります。手動のセグエを利用するか、didSelectRowAtIndexPathでの処理を中止します。

25
Hampden123

ここで何が起こったのかについて少し説明を加えたいと思いました:

ビューが表示される前にprepareForSegueが呼び出されます

viewDidloadは、ビューに最初にアクセスしたときに呼び出されます(ビューは遅延ロードされます)。

おそらく起こったことは、viewprepareForSegueにアクセスして、ビューの読み込みを手動でトリガーしたことです。

通常、フローは次のとおりです。

  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をより早くトリガーできます。

2
Antzi

共有してくれてありがとう、私の問題を理解するのを手伝ってくれました。

私の場合、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 = ...
}
2
Ghar

簡単な解決策は配置することです

[self.tableView reloadData];

viewWillAppear

1
jose mera

動的セルでも同様の問題が発生し、選択するとモーダルが表示されました。 prepareForSeguedidSelect:atIndexPathの前に実行されました。私を助けたのは、ストーリーボードで、動的セルのプロトタイプではなく、コントローラーから開始するようにセグエを再割り当てしたことです。競合状態(?)を解決し、すべてが完全に機能しています!