I have a ViewController that calls viewWillAppear and viewDidAppear without calling viewDidLoad.
How can this be?
Related
In my app, sometimes pushViewController fails for no reason and what happens is very weird. The navigationBar and navigationItem change but the ViewController is not pushed. Then I can tap nothing on the screen. I find that viewWillAppear is called but viewDidAppear isn't called. I push the home button of iPhone to enter background. After entering foreground again, the ViewController is pushed and viewDidAppear is called. I don't know why and when it happens.
normal viewDidAppear callstack
viewDidAppear after enterBackground callstack
If you can repro by:
Try using the left edge pop gesture when there are no view
controllers below it (i.e on root view controllers, your VC-Home
controller)
Try clicking on any UI elements after this.
Then Disable interactivePopGestureRecognizer when current viewController is the firstVC in navigation controller.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
reference:
iOS App Freezes on PushViewController
Is the viewcontroller which you pushed into the view hierarchy overwrite the viewWillAppear/viewDidAppear accidently without calling [super viewWillAppear/viewDidAppear:animated]?
You're probably accidentally calling [super viewDidLoad] inside your viewWillAppear method
For anyone having the same issue as me: Check all your custom views to see if you're not having an infinite loop of layoutSubviews. This is on of the things that happens in between a viewWillAppear and a viewDidAppear.
In my implementation I had a custom Tab bar controller and fore some reason viewDid Appear was empty, putting super calling solved it.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) //was missing this line
}
You know,if you overwrite navigationController.interactivePopGestureRecognizer.delegate and not restore it appropriately, this bug will appear,too
I have a view controller where
- (BOOL)prefersStatusBarHidden {
return YES;
}
is getting called before
- (void)viewDidLoad
{
[super viewDidLoad];
}
I am another view controller where the viewDidLoad is getting called first and then the prefersStatusBarHidden.
I want prefersStatusBarHidden to be called before viewDidLoad.
Please help!
for a simple view controller in a tab bar controller I got this order for iOS 8.3
13:57:46.610 loadView
13:57:46.612 viewDidLoad
13:57:46.612 updateViewConstraints
13:57:46.613 viewWillLayoutSubviews
13:57:46.613 viewDidLayoutSubviews
13:57:46.614 viewWillAppear:
13:57:46.616 prefersStatusBarHidden
13:57:46.616 viewWillLayoutSubviews
13:57:46.616 viewDidLayoutSubviews
13:57:46.712 viewDidAppear:
The reason you see the viewWillLayoutSubviews/viewDidLayoutSubviews calls twice, that any transitioning animation is happening in between.
I would expect that if there is a animation, also the disappearing of a statusbar would be animated and that might be the reason the call for prefersStatusBarHidden happens there.
So whatever you want to do in viewDidLoad is better suited in viewWillLayoutSubviews or viewDidLayoutSubviews
I used this code: https://github.com/vikingosegundo/ofaexample/blob/298c56346f49c467c9f54e9cf18cd5ec604c1fdc/OFAExample/SecondViewController.m
This seems to be the order the methods are called:
initWithCoder:
awakeFromNib
willMoveToParentViewController:
prefersStatusBarHidden
preferredStatusBarUpdateAnimation
loadView
prepareForSegue:sender:
viewDidLoad
extendedLayoutIncludesOpaqueBars
edgesForExtendedLayout
viewWillAppear:
...
Source: https://bradbambara.wordpress.com/2014/07/31/object-life-cycle-uiviewcontroller/
So you need to rethink your architecture so you're not assuming viewDidLoad is called before prefersStatusBarHidden
I have a UIViewController class that contains a WKWebView and implements WKNavigationDelegate.
I would like to detect when a the view controller appears again. I understand the method loadView but, if I push a new view on the stack and then go back from that view to the previous view (my view controller) which method is called on the view controller?
The method that will be called is viewWillAppear:.
If you push to next view then viewDidLoad will be called first
Then viewWillAppear, viewDidAppear
If you pop to previous screen again (your UIViewController) then
viewWillAppear will be called first and after entire view appears
then viewDidAppear will be called..
viewDidAppear is useful in the cases where any method called at viewWillAppear after that you can Load the data at ViewDidAppear..
The ViewControllers viewDidLoad method is only called once when the view is created for the first time.
// viewDidLoad is called only once when the view is created for the first time
- (void) viewDidLoad
{
[super viewDidLoad];
// do your code here
}
You can also implement the below two methods in side your ViewController.m class
// viewWillAppear is called just before the view is about to be appeared
- (void) viewWillAppear
{
[super viewWillAppear];
// do your code here
}
// is called when the view has appeared
- (void) viewDidAppear
{
[super viewDidAppear];
// do your code here
}
I'm implementing my own 'back' button. Where onClick, the following code is executed in the ViewController (VC) being dismissed:
Dismiss current VC (VC#1)
Pop current VC (VC#1) off my custom navigationStack
Get the last VC (VC#2) from the navigationStack, and present it using
presentViewController
What happens is the back works visually works - i.e. current VC disappears, previous VC appears. However, the viewDidLoad method is not called. So the screen isn't updated with data updates from viewDidLoad.
[self dismissCurrentViewController:self completion:^{
[TWStatus dismiss];
FHBaseViewController *vcToDisplay = [[FHDataManager sharedInstance] popNavigationStack];
[vcToDisplay.homeVC presentViewController:vcToDisplay animated:NO completion: ^{ }];
}];
Questions:
I was under the impression that viewDidLoad always gets called when presentViuewController is used??
I 'build' the screen using a method called ONLY from viewDidLoad in VC#2. How is iOS displaying the screen without coming into viewDidLoad?
btw, I'm not using storyboards. Any help is appreciated!
My guess is that viewWillAppear is being called but viewDidLoad is not, at least not when you expect it is. viewDidLoad should be called once, but depending on how you're managing the view controllers, viewDidLoad may not be triggered every time your view appears (which happens after loading).
The completion handler is called after the viewDidAppear: method is called on the presented view controller. from presentViewController doc
so put this in your code with a breakpoint on the call to super and verify it is getting called when this transition occurs.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
edit: since you verified that viewWillAppear is getting called, then I would say that it's coming down to how you are managing the view controller life cycle. Even with a standard UINavigationController, viewDidLoad is not called when a view is shown as a result of popping items on the navigation stack. I would move your logic to viewWillAppear if you are dead set on not using UINavigationController
When I make a back button pragmatically I use:
[self.navigationController popViewControllerAnimated:YES];
This will invoke the viewDidLoad method. Use that instead of your current code.
I'm setting a ViewController using the following code: [detailNav setViewControllers:[NSArray arrayWithObject:vc] animated:NO];
When the ViewController is set in iOS 6 and 7, viewWillAppear, viewDidAppear and viewWillDisappear is called.
However, in iOS 5, these methods are not called.
Edit: pushViewController does not work either:
viewWillDisappear and viewDidDisappear never get called
Turns out somewhere in the ViewControllers hierarchy, automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers was returning NO.
Returning YES fixed the issue.
Shot in the dark but make sure each has the super call example in the viewdidload method it would have this first
[super viewDidLoad];