web-dev-qa-db-ja.com

viewWillAppear、viewDidAppearが呼び出されず、発火しない

(実際の答えを見つけるのにかなりの掘り下げを要したため、これは質問と回答の両方です。)

症状:viewWillAppearviewDidAppearがUIViewControllerで呼び出されていませんでした。

原因:UINavigationControllerまたはUITabBarController(私の場合)をUIViewControllerに埋め込むと、これらのメソッドの呼び出しが中断されます。

解決策:前述のUIViewController/UINavigationControllerを含むUITabBarControllerで手動で呼び出します。

例(projectNavigationControllerUINavigationControllerであると仮定):

void)viewWillAppear:(BOOL)animated {
 [super viewWillAppear:animated]; 
 [projectNavigationController viewWillAppear:animated]; 
} 
 
-(void)viewWillDisappear:(BOOL)animated {
 [super viewWillDisappear:animated]; 
 [projectNavigationController viewWillDisappear:animated]; 
} 
 
-(void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated]; 
 [projectNavigationController viewDidAppear:animated]; 
} 
 
-(void)viewDidDisappear:(BOOL)animated {
 [super viewDidDisappear:animated]; 
 [projectNavigationController viewDidDisappear:animated]; 
} 

私の場合、内部にUITabBarControllerがあり、それに応じてメソッドを呼び出し、すべて解決しました。

(ソリューションの帰属:---(http://davidebenini.it/2009/01/03/viewwillappear-not-being-called-inside-a-uinavigationcontroller/

38
pschang

私は先に進んで@ St3fanに同意せず、反例としてUIKitを使用します。

ただし、埋め込みコントローラーの一般的な知識(またはその欠如)は、適切なUI設計原則によって導かれる必要があります。

最も簡単な反例は、UINavigationControllersに埋め込まれたUITabBarControllersです。これらは至る所に現れます。頭上から、iPhoneのiPodアプリ、iPhoneの電話アプリ内の連絡先。

私はそれらがビューで何をするかをチェックするのに気になるほど興味がありました(「スーパーコントローラー」ビューまたはUIWindowに追加します。サブコントローラービューがSt3fanの推奨に反する、ビュー階層内のスーパーコントローラービューの子孫。

InterfaceBuilderですべてをフックして2つのタブを持つUITabBarControllerベースのアプリを作成する非常に迅速なiPhoneアプリを作成しました。最初のタブは、プレーンなoleを持つUINavigationControllerでしたUIViewControllerルートビューコントローラーであり、2番目のタブが古いUIViewControllerであるので、後でクリックする2番目のタブがありました。

いくつかのNSLogステートメントを振りかけて、コントローラーのさまざまなUIView'sを出力します。

tabBarController.view = <UILayoutContainerView: 0x5b0dc80; ...
navigationController.view = <UILayoutContainerView: 0x59469a0; ...
rootViewController.view = <UIView: 0x594bb70; ...
Superview: <UIViewControllerWrapperView: 0x594cc90; ...
Superview: <UINavigationTransitionView: 0x594a420; ...
Superview: <UILayoutContainerView: 0x59469a0; ... // navigationController.view
Superview: <UIViewControllerWrapperView: 0x594b430; ...
Superview: <UITransitionView: 0x5b0e110; ...
Superview: <UILayoutContainerView: 0x5b0dc80; ... // tabBarController.view
Superview: <UIWindow: 0x5942a30; ...

「Superview」という接頭辞が付いた行は、rootViewController.view'sのスーパービューチェーンを上に向かってnilに到達するまでの出力です。

次に、もちろん、ルートビューコントローラでviewDidDisappearが呼び出されるいくつかの場所のコールスタックを一目で確認します。

最初に、新しいコントローラーがスタックにプッシュされた結果として、ルートコントローラーでviewDidDisappearが呼び出されたときのコールスタック:

-[RootController viewDidDisappear:]
-[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:]
...

次に、一番上のUITabBarControllerで別のタブが選択されたときの呼び出しスタック:

-[RootController viewDidDisappear:]
-[UINavigationController viewDidDisappear:]
-[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:]

したがって、すべての場合において、Appleは、コントローラーが埋め込まれたサブコントローラーのさまざまなviewDidAppearなどのメソッドを呼び出す必要があり、ビューも同様に埋め込まれるべきであると判断しました。 UIKitデザインをフォローするための良いリードとする場合、OPはこの爪を頭に当てます。

10
imaginaryboy

私はこれと同じ状況を見ました。以前は、テーブルセルの選択によってトリガーされたインターフェイスビルダーセグエが機能しなくなりました。コードを少し掘り下げた後、テーブルビューデリゲートのセル選択オーバーライドから呼び出して手動で設定しました。

後で、呼び出されたビューコントローラーでレイアウトを変更しましたが、上記のように、viewDidAppearが呼び出されていないことがわかりました。デバッグ出力は「ネストされたプッシュ操作」などを参照しており、手動のプッシュ操作で自分に大きなコメントがあったため

#warning I SHOULD NOT HAVE TO DO THIS!!

私はセグエコードにブレークポイントを設定しましたが、確かにIBセグエは機能しており、呼び出されたビューでデリゲート呼び出しをめちゃくちゃにしていたのは、テーブルセル選択コードでの手動操作でした。私は手動のコードを削除し、すべてが再び元気です。

ビューがプッシュされた後にセル選択コードが呼び出されるのは奇妙に思えます。呼び出し元で選択したセルのインデックスパスを取得するには、プロトコルとデリゲートを実行する必要があります。

0
Chris Fox