UIViewController viewWillAppear not called when adding as subView
Solution 1
You should add statisticsController
as a child view controller of the controller whose view you're adding it to.
self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;
[self.scrollView addSubview:self.statisticsController.view];
[self addChildViewController:self.statisticsController];
[self.statisticsController didMoveToParentViewController:self];
I'm not sure this will make viewDidAppear
get called, but you can override didMoveToParentViewController:
in the child controller, and that will be called, so you can put any code that you would have put in viewDidAppear
in there.
Solution 2
I encounter -viewWillAppear:
not called problem again. After googling, I came here. I did some tests, and find out that the calling order of -addSubview
and -addChildViewController:
is important.
Case 1. will trigger -viewWillAppear:
of controller, but Case 2, it WON'T call -viewWillAppear:
.
Case 1:
controller?.willMoveToParentViewController(self)
// Call addSubview first
self.scrollView.addSubview(controller!.view)
self.addChildViewController(controller!)
controller!.didMoveToParentViewController(self)
Case 2:
controller?.willMoveToParentViewController(self)
// Call adChildViewController first
self.addChildViewController(controller!)
self.scrollView.addSubview(controller!.view)
controller!.didMoveToParentViewController(self)
Solution 3
By default, appearance callbacks are automatically forwarded to children. It's determined with shouldAutomaticallyForwardAppearanceMethods property. Check value of this propery, if it's NO and if your child viewController should appear right on container's appearance, you should notify child with following methods in container's controller life-cycle implementation:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (UIViewController *child in self.childViewControllers) {
[child beginAppearanceTransition:YES animated:animated];
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.child endAppearanceTransition];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
for (UIViewController *child in self.childViewControllers) {
[child beginAppearanceTransition:NO animated:animated];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.child endAppearanceTransition];
}
Customizing Appearance and Rotation Callback Behavior
Fixed my problem! Hope it would be helpful.
Solution 4
As mentioned in another answer, the parent view controller might not call viewWillAppear
etc. when shouldAutomaticallyForwardAppearanceMethods
is set to false
. UINavigationController
and UITabBarController
are known to do that. In this case, you need to call beginAppearanceTransition(_ isAppearing: Bool, animated: Bool)
on the child view controller with isAppearing
set to true
when the view appears and vice versa.
You have to place these calls at appropriate places in your code, normally when you add and remove your child view controller.
Don't forget to call endAppearanceTransition
on your child view controller when your custom transition has ended, otherwise viewDidAppear
and viewDidDisappear
are not called.
Solution 5
Per Apple (https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html), the correct order of API calls to add a child view controller is:
[self addChildViewController:childVC];
[self.view addSubview:childVC.view];
[childVC didMoveToParentViewController:self];
But I still had the problem where viewWillAppear in the child VC was not sporadically getting called. My issue was that there was a race condition that could cause the code above to get executed before viewDidAppear in the container view controller was called. Ensuring that viewDidAppear had already been called (or deferring the addition of the child VC until it was) solved it for me.
Comments
-
Fogmeister almost 2 years
I have a
UIViewController
that I am loading from inside another view controller and then adding its view to aUIScrollView
.self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"]; self.statisticsController.match = self.match; [self.scrollView addSubview:self.statisticsController.view];
I've put breakpoints in the statistics view controller and
viewDidLoad
is being called butviewWillAppear
isn't.Is it because I'm not pushing it onto the hierarchy or something?
-
sbarow over 10 yearsYip, if a view is added as a subview, viewDidAppear will not be called. You could get around it by manually calling it from the parent views viewDidAppear method
-
sbarow over 10 years
-
Fogmeister over 10 yearsAh, I thought that might be the case. Thanks.
-
-
sbarow over 10 yearsWould this trigger viewDidAppear methods?
-
Fogmeister over 10 yearsHey! This works :D Thanks very much! @sbarow yes it triggers the viewWillAppear method.
-
Craig Siemens over 10 yearsThis will only work on iOS 6, on iOS 5 you will have to call
viewWillAppear:
manually. -
Rafał Augustyniak over 10 yearsThere should be [self.statisticsController willMoveToParentViewController:self] call before [self addChildViewController:self.statisticsController].
-
rdelmar over 10 years@RafałAugustyniak, That's not necessary, it's called automatically by the system. From the docs: "When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it."
-
Fattie over 9 yearstrouble is ... it triggers viewWillAppear twice!! which sucks
-
Alexander Volkov over 9 yearsActually you must first
addChildViewController
, thenaddSubview
. -
zumzum almost 8 yearsyou must first addChildViewController... @AlexanderVolkov is right.
-
Nikolai Ruhe over 7 yearsInteresting. This contradicts Apple's documentation in the view controller programming guide. You should file a bug.
-
Rachit Rawat over 7 yearsThis helped me.
-
SeeMeCode over 6 yearsAny update on this? Seems like a bug to me, but definitely ran into the same thing. Apple's documentation states case 2 is the correct way, and it makes more sense (developer.apple.com/library/content/featuredarticles/…). Maybe I'll file a radar...
-
AechoLiu over 6 years@SeeMeCode, please file a radar. :) I has not touched those codes about 1 year.
-
Markus about 6 yearsCase 2 seems to be working fine. (Xcode 9.3, Swift 4.1)
-
daxh over 5 yearsYou have saved my day!
-
Aleksandr Terentev over 5 yearsit doesn't seem like a bug. UIKit checks shouldAutomaticallyForwardAppearanceMethods flag and call willAppear inside viewWillMoveToWindow methods. If childController hasn't been added yet UIKit 'can't understand" added view is view of childController so there is not enough information to start "appearence forwarding".
-
Gustaf Rosenblad about 5 yearsI can add that this bug happened to us on iOS 10. Worked fine on iOS 11 later.