iPhone viewWillAppearが起動しない


116

私はviewWillAppear、ビュー階層適切に作成しないと問題が発生する人々に関する数多くの投稿を読みました。私の問題は、それが何を意味するのか理解できないことです。

そのコントローラーでを作成しRootViewControllerて呼び出しaddSubViewた場合、追加されたビューがviewWillAppearイベントに関連付けられると期待します。

viewWillAppearすべてのレベルでイベントを正常に受信する複雑なプログラムビュー階層の例はありますか?

Appleのドキュメントの状態:

警告:ビューコントローラーに属するビューがビュー階層に直接追加された場合、ビューコントローラーはこのメッセージを受け取りません。ビューをビュー階層に挿入または追加し、ビューにビューコントローラーがある場合は、関連するビューコントローラーにこのメッセージを直接送信する必要があります。このメッセージをビューコントローラーに送信しないと、関連するアニメーションが表示されなくなります。

問題は、これを行う方法を説明していないことです。「直接」とはどういう意味ですか?どのように「間接的に」ビューを追加しますか?

私はCocoaとiPhoneにかなり慣れていないので、基本的なHello Worldのがらくた以外に、Appleの便利な例があるといいですね。


この問題は、UIViewControllerサブクラスの使用目的を一般的に誤解していることに気づくまで続きました。この質問をチェックしてください。 stackoverflow.com/questions/5691226/...
averydev

7
ご注意ください!!! iOS 5ではもう当てはまりません!!! 自動的にviewWillAppearとviewDidAppearを呼び出します
ヴィレーム・クルツ

回答:


55

ナビゲーションコントローラーを使用してデリゲートを設定した場合、view {Will、Did} {Appear、Disappear}メソッドは呼び出されません。

代わりに、ナビゲーションコントローラのデリゲートメソッドを使用する必要があります。

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

2
ナビゲーションコントローラーのデリゲートを設定していませんでしたが、それでもメソッドが呼び出されませんでした。とにかく、私はそれを設定し、それから私はあなたが上で述べた方法を使いました。ありがとう。
Dimitris

私はディミトリスと同じものを見ています
jkp '14

7
など:これは真実ではない:navigationControllerのデリゲートを設定し、それにビューをプッシュすると、viewWillAppearを発生させます、私はちょうどこのiOS4をしてiOS5をでテスト
DaGaMs

Swift 3:func navigationController(_ navigationController:UINavigationController、willShow viewController:UIViewController、animated:Bool){} AND func navigationController(_ navigationController:UINavigationController、didShow viewController:UIViewController、animated:Bool){}
Naloiko Eugene

28

私はこれと同じ問題に遭遇しました。viewWillAppearメッセージをサブビューとして追加する前に、メッセージをビューコントローラに送信するだけです。(アニメーション化されているかどうかをビューコントローラに伝えるBOOLパラメータが1つあります。)

[myViewController viewWillAppear:NO];

MetronomeサンプルのRootViewController.mを見てください。

(私は実際にAppleのサンプルプロジェクトが素晴らしいと思いました。HelloWorld以外にもたくさんあります;)


3
実際には、サブビューに追加した後で、viewWillAppearを呼び出す必要があります。そうしないと、IBOutlets / IBActionsは接続されません。
4thSpace 2009年

2
はい、その後。XIBからサブビューを作成しましたが、viewWillAppearは呼び出されませんでした。自分でそれを呼び出すと、すべてうまくいきます。
JOM 2010

ありがとうございました!これはまさに私にとってそれでした。を介して手動でサブビューを追加していました[scrollView addSubview:controller.view];[controller viewWillAppear:NO];後で行を追加して出来上がり!魅力のように働いた。
Rob S.

ほとんどの場合、これは、UIViewControllerが別のUIViewControllerによって制御されるビューのサブビューであるビューを制御しているためです。これは意図された設計パターンではありません。詳細については、この投稿をご覧ください。stackoverflow.com/questions/5691226/...
averydev

6
ご注意ください!!! iOS 5ではもう当てはまりません!!! viewWillAppearおよびviewDidAppearを自動的に呼び出します。手動で呼び出すと、2回呼び出されます。
ヴィレーム・クルツ

18

私はついにこれの解決策を見つけました!

UINavigationControllerDelegate

その要点は、ナビゲーションコントロールのデリゲートをそれが含まれているビューコントローラーに設定し、実装することUINavigationControllerDelegateと、2つのメソッドです。鮮やかさ!私はとても興奮しています、私は最終的に解決策を見つけました!


rootviewcontrollerをnavigationcontrollerのデリゲートとして割り当てる方法は?
Gargo、

1
動かない!アプリを最小化して最大化してみてください
Vyachaslav Gerchicov 2017

8

私は同じ問題を抱えていました。私のアプリケーションには2つのナビゲーションコントローラーがあり、それぞれに同じビューコントローラーをプッシュすると、1つのケースでは機能し、別のケースでは機能しませんでした。つまり、最初UINavigationControllerのでまったく同じView ControllerをviewWillAppearプッシュしたときに、が呼び出されましたが、2番目のナビゲーションコントローラーでプッシュされたときは呼び出されませんでした。

次に、この投稿に遭遇しましたUINavigationControllerはviewWillAppear / viewWillDisappearメソッドを呼び出す必要があります

そして、私の2番目のナビゲーションコントローラーが再定義したことに気づきましたviewWillAppear。コードをスクリーニングすると、私が電話していないことがわかりました

[super viewWillAppear:animated];

私はそれを追加し、うまくいきました!

ドキュメントは言う:

このメソッドをオーバーライドする場合は、実装のある時点でsuperを呼び出す必要があります。


ここも同じです。スーパーを呼び出さないことによって台無しに。
olivaresF

5

ナビゲーションコントローラーを使用しています。別のレベルのデータに降りたい、またはカスタムビューを表示したい場合は、以下を使用します。

[self.navigationController pushViewController:<view> animated:<BOOL>];

これを行うと、viewWillAppear関数が起動します。私は実際のaddSubViewメソッドを自分で呼び出していないので、これは「間接的」と見なされます。ナビゲーションコントローラーを使用しているかどうかはわかりませんので、これがアプリケーションに100%適用できるかどうかはわかりませんが、おそらく手掛かりになるでしょう。


5

ありがとうiOS 13。

ViewWillDisappearViewDidDisappearViewWillAppearおよび ViewDidAppear画面全体をカバーしていない新しいモーダルプレゼンテーションを使用してiOSの13に提示するビューコントローラに呼び出されません。

クレジットはArek Holkoに送られます。彼は本当に私の日を救った。

ここに画像の説明を入力してください


4

まず、アップルのドキュメントに記載されているように、タブバーはルートレベルにある、つまりウィンドウに追加されている必要があります。これが正しい動作の鍵です。

次に、/ を使用して通知を手動で転送できます、ビュー呼び出しの階層全体を正しく機能させるには、手動で呼び出すだけでよいことがわかりましたUITabBarDelegateUINavigationBarDelegate

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

そして

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

..それぞれのコントローラーでビューコントローラーを設定する前に(割り当て直後に)一度だけ。それ以降、子ビューコントローラでこれらのメソッドを正しく呼び出しました。

私の階層は次のとおりです:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

タブ/ナビゲーションコントローラーで前述のメソッドを初めて呼び出すだけで、すべてのイベントが正しく転送されることが保証されました。UINavigationBarDelegate/ UITabBarControllerDelegateメソッドから手動で呼び出す必要がなくなりました。

傍注:不思議なことに、それが機能しなかった場合、プライベートメソッド

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

..機能している実装のコールスタックから確認できますが、通常はviewWill/Did..メソッドを呼び出しますが、(呼び出された場合でも)上記を実行するまではそうではありませんでした。

UITabBarControllerウィンドウレベルであることが非常に重要であり、ドキュメントはこれを裏付けているようです。

それが明確であるように願って、さらなる質問に答えて幸せです。


3

答えが受け入れられず、人々が(私がしたように)ここに上陸したので、私は私のバリエーションを与えます。それが元々の問題だったのかどうかはわかりませんが。ナビゲーションコントローラをサブビューとして別のビューに追加する場合は、次のように、viewWillAppear / Dissappearなどのメソッドを自分で呼び出す必要があります。

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

例を完成させるためだけに。このコードは、ナビゲーションコントローラーを作成してビューに配置したビューに追加したViewControllerに表示されます。

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.hは次のようになります

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

nibファイルにはビューがあり、このビューの下には、イメージと、コントローラーを配置するコンテナー(別のビュー)のラベルがあります。これはクライアントの仕事だったので、私はいくつかのことをスクランブルする必要がありました。

代替テキスト


3

呼び出しによってビューが「直接」追加されます [view addSubview:subview]ます。ビューは、サブビューを交換するタブバーやナビゲーションバーなどの方法によって「間接的に」追加されます。

を呼び出すときはいつでも[view addSubview:subviewController.view]、次に呼び出す必要があります[subviewController viewWillAppear:NO](または場合によってはYES)。

ゲームの従属画面に独自のカスタムルートビュー管理システムを実装したときに、この問題が発生しました。手動でviewWillAppearへの呼び出しを追加すると、問題が解決しました。


3

これを行う正しい方法は、UIViewController包含APIを使用することです。

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}

これは完全に正しい最新のソリューションです(iOS 9、8、7)。また、埋め込みビューコントローラをオンザフライで変更する場合は、[viewController willMoveToParentViewController:nil]を呼び出す必要があります。[viewController.view removeFromSuperview]; [viewController removeFromParentViewController];
Eli Burke

1
この場合、viewWillAppear:まだ呼び出されない可能性があります
Vyachaslav Gerchicov

2

私はこのコードをプッシュおよびポップビューコントローラーに使用します。

押す:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

ポップ:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

..それは私にとってはうまくいきます。


2

よくある間違いは次のとおりです。1つのビューUIView* aともう1 つのビューがありますUIView* b。bをサブビューとしてaに追加します。bでviewWillAppearを呼び出そうとすると、aのサブビューであるため、呼び出されません。


2

iOS 13は私のアプリをここでお尻に食い込ませました。iOS 13以降の動作の変化に気付いた場合は、プッシュする前に次のように設定してください。

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

また、属性インスペクタの.storyboardで設定する必要がある場合もあります(プレゼンテーションを全画面に設定)。

これにより、アプリは以前のバージョンのiOSと同じように動作します。


1

私はこれについて100%確信はありませんが、ビュー階層にビューを直接追加することは、新しいビューコントローラーをナビゲーションコントローラーのスタックにプッシュする代わり-addSubview:に、ビューコントローラーのビュー(など[viewController.view addSubview:anotherViewController.view])を呼び出すことを意味すると思います。


1

サブビューを追加しても、ビューが表示されるとは限らないので、クラスのメソッドが自動的に呼び出されることはないと思います


1

それらが「直接」に意味することは、UINavigationControllerをアプリケーションのUIWindowの唯一のサブビューとして設定するxcodeの「Navigation Application」テンプレートと同じ方法で接続することによると思います。

そのテンプレートを使用することが、UINavigationController内のコントローラーのプッシュ/ポップ時にオブジェクトViewControllersで呼び出されるWill / Did / Appear / Disappearメソッドを取得できる唯一の方法です。RootControllerに実装して(子)NavigationControllerに渡すなど、ここでの回答の他のソリューションはどれもうまくいきませんでした。これらの関数(will / did / appear / disappear)は、トップレベルのVC、「ログイン」、navigationVCを表示/非表示にしたときにRootControllerでのみ呼び出され、ナビゲーションコントローラーのサブVCでは呼び出されなかったため、 Nav VCに「パススルー」します。

私は、UINavigationControllerのデリゲート機能を使用して、アプリのフォローアップ機能を必要とする特定の遷移を探すことになりましたが、それは機能しますが、非表示機能と表示機能の両方を「シミュレート」するには、もう少し作業が必要です。

また、今日何時間もこの問題に頭をぶつけてから動作させることは原則の問題です。カスタムRootControllerと子ナビゲーションVCを使用して機能するコードスニペットがあれば、大歓迎です。


1

これが誰かを助ける場合。同様の問題が発生ViewWillAppearしましたUITableViewController。何度も遊んでみたところ、問題はUINavigationController自分を制御しているUITableViewがルートビューにないことであることに気付きました。私がそれを修正すると、それは今やチャンピオンのように働いています。


あなたがそれをした「方法」を共有していただけませんか?
Brabbeldas 2017年

1

私は自分でこの問題を抱えていて、それを修正するのに3時間(うち2回はグーグル)かかりました。

助けになったのは、デバイス/シミュレーターからアプリを削除し、クリーンアップしてから再度実行することでした。

それが役に立てば幸い


1
[self.navigationController setDelegate:self];

デリゲートをルートビューコントローラーに設定します。


1

Swiftの場合。まず、viewWillAppearで呼び出したいものを呼び出すプロトコルを作成します

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

次に、クラスを作成します

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

3番目に、ForceUpdateOnViewAppearのインスタンスを、Navigation Controllerにアクセスできる適切なクラスのメンバーにし、Navigation Controllerが存在する限り存在するようにします。たとえば、ナビゲーションコントローラのルートビューコントローラ、またはそれを作成または表示するクラスの場合があります。次に、ForceUpdateOnViewAppearのインスタンスをできるだけ早くナビゲーションコントローラーデリゲートプロパティに割り当てます。


0

私の場合、問題はカスタム遷移アニメーションにありました。セット時modalPresentationStyle = .custom viewWillAppear呼び出さないように

カスタム遷移アニメーションクラスでは、呼び出しメソッドが必要です: beginAppearanceTransitionおよびendAppearanceTransition


0

私の場合、それはiOS 12.1エミュレータの奇妙なバグでした。実際のデバイスで起動した後に消えた。


0

この問題を解決するクラスを作成しました。ナビゲーションコントローラーのデリゲートとして設定し、ビューコントローラーに単純な1つまたは2つのメソッドを実装するだけです。これは、ビューが表示されようとしているとき、またはNavigationControllerを介して表示されたときに呼び出されます。

これがコードを示すGISTです


0

ViewWillAppearはUIViewControllerクラスのオーバーライドメソッドであるため、subViewを追加してもviewWillAppearは呼び出されません。


0

私の問題は、セグエから巻き戻したときにviewWillAppearが呼び出されなかったことです。答えは、ビューコントローラーのアンワインドセグエにviewWillAppear(true)への呼び出しを配置することでした。

@IBAction func unwind(unwindSegueの場合:UIStoryboardSegue、ViewController後続のVC:任意){

   viewWillAppear(true)
}

-2

これが私が解決した問題と同じかどうかはわかりません。
「[self methodOne]」などの通常の方法ではメソッドが実行されない場合があります。

試す

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

問題はviewWillAppearまったく呼ばれていません
Vyachaslav Gerchicov

-3

常に1つのUIViewControllerのみをアクティブにする必要があります。操作するすべてのサブビューは、まさに-サブビュー-つまりUIViewでなければなりません。

私はビュー階層を管理するために簡単な手法を使用しており、この方法で作業を始めて以来、まだ問題に遭遇していません。2つの重要なポイントがあります。

  • アプリの「画面の価値」を管理するには、単一のUIViewControllerを使用する必要があります
  • UINavigationControllerを使用してビューを変更する

「画面の価値」とはどういう意味ですか?意図的に少しあいまいですが、一般的にはアプリの機能またはセクションです。背景画像が同じでオーバーレイ/ポップアップが異なる画面がいくつかある場合は、1つのビューコントローラと複数の子ビューである必要があります。2つのView Controllerを使用していることはありません。画面の特定の領域を複数のビューコントローラーで表示したい場合は、1つのビューコントローラーでUIViewをインスタンス化して、別のビューコントローラーのサブビューとして追加できます。

UINavigationControllerについて-これはあなたの親友です!ナビゲーションバーをオフにして、アニメーションにNOを指定すると、オンデマンドで画面を切り替えることができます。ビューコントローラーが階層内にある場合は、プッシュおよびポップできます。または、ビューコントローラーの配列(単一のVCを含む配列を含む)を準備し、setViewControllersを使用してそれをビュースタックに設定できます。これにより、VCを変更する自由が完全に得られますが、Appleの予想モデル内で作業し、すべてのイベントなどを適切に発生させるという利点がすべて得られます。

アプリを起動するときに毎回行うことは次のとおりです。

  • ウィンドウベースのアプリから始める
  • ウィンドウのrootViewControllerとしてUINavigationControllerを追加します。
  • 最初のUIViewControllerをナビゲーションコントローラーのrootViewControllerとして追加します

(ウィンドウベースから始めることに注意してください-私は自分で構築したいので、それらがどのように構築されているかを正確に把握しています。ビューベースのテンプレートでうまく機能するはずです)

すべてのイベントは正しく発生し、基本的には人生は良好です。その後、アプリの重要な部分を記述し、ビュー階層を手動でハッキングして形を整えようとすることを混乱させることなく、すべての時間を費やすことができます。


複数のView Controllerをアクティブにすることには何の問題もありません。UIViewControllerには、階層を構築できるメソッドがあります([addChildViewController:]など)。
Richard

1
はいそれは今します。2011年はそうではありませんでした。当時の答えは正確でしたが、確かに正確ではありません。
Nigel Flack
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.