iPhone viewWillAppear not firing

Viewed 104528

I've read numerous posts about people having problems with viewWillAppear when you do not create your view hierarchy just right. My problem is I can't figure out what that means.

If I create a RootViewController and call addSubView on that controller, I would expect the added view(s) to be wired up for viewWillAppear events.

Does anyone have an example of a complex programmatic view hierarchy that successfully receives viewWillAppear events at every level?

Apple's Docs state:

Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.

The problem is that they don't describe how to do this. What does "directly" mean? How do you "indirectly" add a view?

I am fairly new to Cocoa and iPhone so it would be nice if there were useful examples from Apple besides the basic Hello World crap.

27 Answers

If you use a navigation controller and set its delegate, then the view{Will,Did}{Appear,Disappear} methods are not invoked.

You need to use the navigation controller delegate methods instead:

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

I've run into this same problem. Just send a viewWillAppear message to your view controller before you add it as a subview. (There is one BOOL parameter which tells the view controller if it's being animated to appear or not.)

[myViewController viewWillAppear:NO];

Look at RootViewController.m in the Metronome example.

(I actually found Apple's example projects great. There's a LOT more than HelloWorld ;)

I finally found a solution for this THAT WORKS!

UINavigationControllerDelegate

I think the gist of it is to set your nav control's delegate to the viewcontroller it is in, and implement UINavigationControllerDelegate and it's two methods. Brilliant! I'm so excited i finally found a solution!

Thanks iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppear and ViewDidAppear won't get called on a presenting view controller on iOS 13 which uses a new modal presentation that doesn't cover the whole screen.

Credits are going to Arek Holko. He really saved my day.

enter image description here

I just had the same issue. In my application I have 2 navigation controllers and pushing the same view controller in each of them worked in one case and not in the other. I mean that when pushing the exact same view controller in the first UINavigationController, viewWillAppear was called but not when pushed in the second navigation controller.

Then I came across this post UINavigationController should call viewWillAppear/viewWillDisappear methods

And realized that my second navigation controller did redefine viewWillAppear. Screening the code showed that I was not calling

[super viewWillAppear:animated];

I added it and it worked !

The documentation says:

If you override this method, you must call super at some point in your implementation.

I've been using a navigation controller. When I want to either descend to another level of data or show my custom view I use the following:

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

When I do this, I do get the viewWillAppear function to fire. I suppose this qualifies as "indirect" because I'm not calling the actual addSubView method myself. I don't know if this is 100% applicable to your application since I can't tell if you're using a navigation controller, but maybe it will provide a clue.

A very common mistake is as follows. You have one view, UIView* a, and another one, UIView* b. You add b to a as a subview. If you try to call viewWillAppear in b, it will never be fired, because it is a subview of a

iOS 13 bit my app in the butt here. If you've noticed behavior change as of iOS 13 just set the following before you push it:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

You may also need to set it in your .storyboard in the Attributes inspector (set Presentation to Full Screen).

This will make your app behave as it did in prior versions of iOS.

I'm not 100% sure on this, but I think that adding a view to the view hierarchy directly means calling -addSubview: on the view controller's view (e.g., [viewController.view addSubview:anotherViewController.view]) instead of pushing a new view controller onto the navigation controller's stack.

I think that adding a subview doesn't necessarily mean that the view will appear, so there is not an automatic call to the class's method that it will

In my case problem was with custom transition animation. When set modalPresentationStyle = .custom viewWillAppear not called

in custom transition animation class need call methods: beginAppearanceTransition and endAppearanceTransition

For Swift. First create the protocol to call what you wanted to call in viewWillAppear

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

Second, create the class

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

}

Third, make the instance of ForceUpdateOnViewAppear to be the member of the appropriate class that have the access to the Navigation Controller and exists as long as Navigation controller exists. It may be for example the root view controller of the navigation controller or the class that creates or present it. Then assign the instance of ForceUpdateOnViewAppear to the Navigation Controller delegate property as early as possible.

In my case that was just a weird bug on the ios 12.1 emulator. Disappeared after launching on real device.

I have created a class that solves this problem. Just set it as a delegate of your navigation controller, and implement simple one or two methods in your view controller - that will get called when the view is about to be shown or has been shown via NavigationController

Here's the GIST showing the code

ViewWillAppear is an override method of UIViewController class so adding a subView will not call viewWillAppear, but when you present, push , pop, show , setFront Or popToRootViewController from a viewController then viewWillAppear for presented viewController will get called.

My issue was that viewWillAppear was not called when unwinding from a segue. The answer was to put a call to viewWillAppear(true) in the unwind segue in the View Controller that you segueing back to

@IBAction func unwind(for unwindSegue: UIStoryboardSegue, ViewController subsequentVC: Any) {

   viewWillAppear(true)
}
Related