How to automatically call a method after popping a view controller off the stack on the iPhone - iphone

I need to update the parent view on an iPhone after popping a child view off the navigation stack. How can I setup the parent view to be notified or receive an automatic method call when the child is popped off the stack and the parent becomes visible again?
The user enters data on the child page that I want to display on the parent page after the user is done and pops the view.
Thanks for you help!

I just resolved this self same problem - and the answers above are almost correct, they just forgot about setting the delegate.
I have a root view controller that displays the size of a list, calls a child view controller that may alter the size of a list, and must update the size upon return.
When I create my parent view (SettingsView below), and add it as the root view of a UINavigationController, I make sure to set the UINavigationController's delegate before I display the view - that's the key part:
SettingsView *sv = [[SettingsView alloc] initWithNibName:#"SettingsView" bundle:nil];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:sv];
[nc setDelegate:sv];
In the parent view, implement the UINavigationControllerDelegate protocol:
#interface SettingsView : UIViewController <UINavigationControllerDelegate>
and provide the willShowViewController method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Your code to update the parent view
}
This is called after the child view is dismissed, and before the parent view is redisplayed.

I had the need to do something like this as well. In the ViewController that owned my UINavigationController, I had to implement willShowViewController, like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
}
That method is called whenever the UINavigationController changes views. If I'm understanding your question correctly, I think this should do what you want.

I think there is some confusion here. UIViews are not pushed to and popped from the UINavigationController's stack. What is being pushed and popped is UIViewControllers, which in turn handle one or (more often) several views each.
Fortunately, the UIViewController has these methods:
-(void) viewWillAppear:(BOOL)animated;
-(void) viewDidAppear:(BOOL)animated;
-(void) viewWillDisappear:(BOOL)animated;
-(void) viewDidDisappear:(BOOL)animated;
These are called whenever the view is about to (dis)appear, or has just (dis)appeared. I works with tab bars, modal views and navigation controllers. (And it's a good idea to make use of these when you implement custom controllers.)
So in your case, if I understand correctly, you simply have to override the viewWillAppear: or viewDidAppear: method on what you call the "parent page" (which is presumably handled by a UIViewController) and put in code to update the appearance of the page to reflect the data just entered.
(If I remember correctly, you must make sure that the UINavigationController gets a viewWill/DidAppear: message when it is first displayed, in order for these messages to later be sent to its child controllers. If you set this up with a template or in IB you probably don't have to worry about it.)

Felixyz answer did the trick for me. Calling the view will appear method will run the code in it every time the view appears. Different from view did load, which runs its code only when the view is first loaded. So your parent view would not update itself if a child view altered the info displayed in the parent, and was then popped off the sack. But if the parents calls view will appear, the code gets ran every time the view shows back up.
Make sure to call the super method at the same time. Proper implementation would look like this:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"View Appearing");
}

If you need to notify one controller to another you may use delegation pattern as described here (see 2nd answer).
Unfortunately there is no automatic notification(AFAIK) for exact task as you described.
To meet your needs you may send message to delegate (i.e. to your parent controller) in viewWillDisappear function of your child controller.

Related

viewWillAppear does not run when using addSubView!

I'm stuck! I can't see why viewWillAppear doesn't run in my code but viewDidLoad runs. If I understand it correctly viewDidLoad runs once on the first instance and viewWillAppear runs every time a view is added to the stack of views to display.
I see others have had this issue but some how their solutions of calling viewWillAppear directly causes my app to crash. Other solutions were related to Navigation Controller and pushingView's but thats not what i'm using either! What am I missing?
Thanks in advance for your help! :)
See below:
View Controller #1 - Currently being displayed on screen
-(IBAction)someButtonPressed:(id)sender{
NSLog(#"FirstViewController - someButtonPressed");
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.myLocation = self.myLocation;
secondViewController.myDatabase = self.myDatabase;
[self.view addSubview:secondViewController.view];
//[secondViewController viewWillAppear:YES];
}
SecondViewController:
- (void)viewWillAppear:(BOOL)animated {
NSLog(#"SecondViewController - viewWillAppear");
[super viewWillAppear:animated];
// updating ivars with data
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(#"SecondViewController - viewDidLoad");
[super viewDidLoad];
}
If I understand it correctly viewDidLoad runs once on the first instance and viewWillAppear runs every time a view is added to the stack of views to display.
-viewDidLoad is called every time a UIViewController's view is loaded. That may be many times during a single controller's life as the view may be unloaded to free up memory when it is not visible and reloaded, triggering another call to -viewDidLoad, when needed.
-viewWillAppear: is called when a UIViewController's view becomes visible. However UIKit assumes that UIViewController's views will fill their window. Nesting UIViewControllers' views is an example of abusing UIViewControllers and will result in unexpected behavior. As you have seen.
See About Custom View Controllers in the View Controller Programming Guide for iOS:
Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy. In iPhone applications, the views in a view hierarchy traditionally cover the entire screen, but in iPad applications they may cover only a portion of the screen. The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
If you wrote a custom UIViewController Container you might have overwritten the following method, which leads to your described behavior.
- (BOOL)shouldAutomaticallyForwardAppearanceMethods{
return NO;
}
In this case you have to manually handle beginAppearanceTransition/endAppearanceTransition.
See Apples View Controller Containment article
viewWillAppear: is called when a view controller is displayed in one of the normal ways (e.g. by selecting a tab in a UITabBarController, by pushing onto a UINavigationController, by being popped back to in a UINavigationController, by being presented with presentModalViewController:animated, by being uncovered after dismissModalViewControllerAnimated:, etc). Just displaying a view with addSubview: does not call the method.
It is possible to correctly call viewWillAppear: manually, but in general it's better to use one of the normal ways mentioned above.
Just try this.. I got it working :)
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"SecondViewController - viewWillAppear");
// updating ivars with data
}
When you push view or present a view controller by pushViewController:animated or presentModelViewController:animated:, they will call viewWillAppear:animated:, and else method for you. But if you addSubview: manually, you need to call those method by self.

Why isn't viewWillDisappear or viewDidAppear being called?

I have a UINavigationController with a UITableView as my main menu. User clicks on a cell and a new view is pushed on the stack. In one case I push another UITableView that needs a toolbar. So on that 2nd tableView's init I setup the self.toolbarItems property with the correct items. But then I need to call [self.navigationController setToolbarHidden:NO animated:YES]; So it makes sense to call this in the viewDidAppear or viewWillAppear method. But I put it in those methods and find out (Also via NSLog) that they never get called. The same goes for hiding it in viewWillDisappear or viewDidDisappear. Why don't these methods get called? Where should I be doing this hiding/showing of the toolbar then?
I have noticed behavior where if a parent controller (like UINavigationController or UITabBarController) never get's viewWill/DidAppear called on it, it won't call it on the child controllers either. So make sure that in the code where you create the parent controller, you call viewWillAppear, show it, then call viewDidAppear. Then it should make those calls on it's child controllers as is appropriate.
Double check the parent controller is having those methods called, and call them yourself if they are not.
Yes Its true
you can do this by first write this code in
- (void)viewDidLoad {
self.navigationController.delegate = self;
}
And then write the code which you want to write in viewWillAppear
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController isKindOfClass:[self class]]) {
//write your code here
}
}
Although you solved your problem, in case someone comes along in the future another problem could have been that you forgot the animated: argument to either method - that is to say, the format of the method needs to look like:
- (void) viewWillAppear:(BOOL)animated
i noticed the same issue in iOS7. When i'm using both tab bar (2 buttons A, B) and navigation controller.
A has two views. One with tableview and second displays data according to the selection from the table view.
B has is the only view.
Button which is refer to another separate view D, placed in both tab bar views (A & B) and in both views of A.
Problem arises when i click the button from tab item B, viewWillAppear and viewDidLoad not called.
So i solved this issue by presentModalViewController:animated: and to come back i used dismissModalViewControllerAnimated:, just when i go to view D from tab item B.

Invocation of ViewDidLoad after initWithNibName

It appears that ViewDidLoad() is sent to a ViewController only after its View is physically displayed (i.e. via NavigationController pushViewController), and not immediately after initWithNibName(). Is this a behavior I can rely on? I would like to get the chance to set the member variables of my view so that all the members are valid by the time ViewDidLoad() is invoked.
You can set up member variables and other such things in initWithNibName:bundle:.
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
if (self = [super initWithNibName:nibName bundle:nibBundle]) {
// set up ivars and other stuff here.
someIvar = someValue;
}
return self;
}
You are correct that viewDidLoad: is only sent when the view is physically displayed, i.e when it is added to some visible view (which may sometimes be never if the user does not reach that view). So it's useful to split the functionality and think about what you can do at init time and what happens at view load time.
As Marcelo Cantos notes in the comment, viewDidLoad: is generally a fine place to do all sorts of setup work, using the concept of "lazy loading," so that you defer the setup until as late time as possible.
viewDidLoad is called before a view controller is displayed for the first time, not immediately after initWithNibName. For example, if you have a tab bar controller, all of the child view controllers will be initd at launch, but viewDidLoad will only be called when you click on the appropriate tab the first time. It's generally a good idea to initialize memory-intensive items in viewDidLoad, so as to avoid using unnecessary memory.
I found that if I override initiWithNibName in the view controller, the viewDidLoad method is not called. I have to call it manually [self viewDidLoad]. But if I do not override initWithNibName: viewDidLoad is called. I am working with 4 view controllers in tab bar controller. the tab bar controller is loaded from another view.
Sorry to unearth an old thread, but this solved it for me...
-(void)viewDidLoad is only called after -(void)loadView has done its thing. In the docs for loadView:
The view controller calls this method when its view property is requested but is currently nil.
My view controller only has viewDidLoad called after its view is request by a UITabBarItem, meaning viewDidLoad is only called in the viewController once the tab bar button is pressed. I, like the OP, want viewDidLoad to be called directly after the nib is loaded, so it's contents (titles, etc) can be populated before the user clicks the tab button.
So, after calling "self = [super initWithNibName:#"nibName" bundle:nil];" in the view controller's custom initialiser, I immediately called '[self view]' afterwards. As the view is requested earlier than when it is requested by the UITabBarItem (which calls 'addSubview'), the view is initialised fully during initialisation, rather than when requested.
Hope this helps.

How do I have a view controller run updating code when it is brought to the top of the stack of views?

I have a viewController (Planner) that loads two view controllers (InfoEditor and MonthlyPlan) when the application starts. MonthlyPlan is hidden behind InfoEditor (on load).
So my question is when I exchange InfoEditor for MonthlyPlan (MonthlyPlan gets brought to the top) how can I have data on the MonthlyPlan view be updated. An NSLog in viewDidLoad is being called when the application starts (which makes sense.) NSLogs in viewDidAppear and viewWillAppear aren't doing anything.
Any ideas?
Thanks!
-- Adding more details --
I'm creating the view hierarchy myself. A simple viewController that is just loading two other viewControllers. The two child viewControllers are loaded at the same time (on launch of application.) To exchange the two views I'm using this code:
[self.view exchangeSubviewAtIndex:1 withSubviewAtIndex:0];
The exchanging of the views is fine. The part that is missing is just some way of telling the subview, you're in front, update some properties.
There's a lack of details here. How are you "exchanging" the two views?
If you were using a UINavigationController as the container then viewWillAppear/viewDidAppear would be called whenever you push/pop a new viewController. These calls are made by the UINavigationController itself. If you ARE using a UINavigationController then make sure you have the prototypes correct for these functions.
- (void)viewWillAppear:(BOOL)animated
If you are trying to implement a view hierarchy yourself then you may need to make these calls yourself as part of activating/deactivating the views. From the SDK page of viewWillAppear;
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.
Update:
With the new details the problem is clear: This is a situation where you must send the disappear/appear messages yourself as suggested by the SDK. These functions are not called automagically when views are directly inserted/removed/changed, they are used by higher-level code (such as UINavigationController) that provides hierarchy support.
If you think about your example of using exchangeSubView then nothing is disappearing, one view just happens to cover the other wholly or partially depending on their regions and opacity.
I would suggest that if you wish to swap views then you really do remove/add as needed, and manually send the viewWillAppear / viewWillDisappear notifications to their controllers.
E.g.
// your top level view controller
-(void) switchActiveView:(UIViewController*)controller animated:(BOOL)animated
{
UIController* removedController = nil;
// tell the current controller it'll disappear and remove it
if (currentController)
{
[currentController viewWillDisapear:animated];
[currentController.view removeFromSuperView];
removedController = currentController;
}
// tell the new controller it'll appear and add its view
if (controller)
{
[controller viewWillAppear:animated];
[self.view addSubView:controller.view];
currentController = [controller retain];
}
// now tell them they did disappear/appear
[removedController viewDidDisappear: animated];
[currentController viewDidAppear: animated];
[removedController release];
}
I would just add an updataData method to each subview and call it at the same time you bring it to the front. You would need to add a variable to your root view controller to track the active subView:
[self.view exchangeSubviewAtIndex:1 withSubviewAtIndex:0];
if (subView1IsActive) [subView1Controller updateData];
else [subView2Controller updateData];

iPhone viewWillAppear not firing

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.
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.
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.
Firstly, the tab bar should be at the root level, ie, added to the window, as stated in the Apple documentation. This is key for correct behavior.
Secondly, you can use UITabBarDelegate / UINavigationBarDelegate to forward the notifications on manually, but I found that to get the whole hierarchy of view calls to work correctly, all I had to do was manually call
[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];
and
[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];
.. just ONCE before setting up the view controllers on the respective controller (right after allocation). From then on, it correctly called these methods on its child view controllers.
My hierarchy is like this:
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
Just calling the mentioned methods on the tab/nav controller the first time ensured that ALL the events were forwarded correctly. It stopped me needing to call them manually from the UINavigationBarDelegate / UITabBarControllerDelegate methods.
Sidenote:
Curiously, when it didn't work, the private method
- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController
.. which you can see from the callstack on a working implementation, usually calls the viewWill/Did.. methods but didn't until I performed the above (even though it was called).
I think it is VERY important that the UITabBarController is at window level though and the documents seem to back this up.
Hope that was clear(ish), happy to answer further questions.
As no answer is accepted and people (like I did) land here I give my variation. Though I am not sure that was the original problem. When the navigation controller is added as a subview to a another view you must call the viewWillAppear/Dissappear etc. methods yourself like this:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[subNavCntlr viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[subNavCntlr viewWillDisappear:animated];
}
Just to make the example complete. This code appears in my ViewController where I created and added the the navigation controller into a view that I placed on the view.
- (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];
}
the .h looks like this
#interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
IBOutlet UIView *subNavContainer;
UINavigationController *subNavCntlr;
}
#end
In the nib file I have the view and below this view I have a label a image and the container (another view) where i put the controller in. Here is how it looks. I had to scramble some things as this was work for a client.
Views are added "directly" by calling [view addSubview:subview].
Views are added "indirectly" by methods such as tab bars or nav bars that swap subviews.
Any time you call [view addSubview:subviewController.view], you should then call [subviewController viewWillAppear:NO] (or YES as your case may be).
I had this problem when I implemented my own custom root-view management system for a subscreen in a game. Manually adding the call to viewWillAppear cured my problem.
Correct way to do this is using UIViewController containment 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];
}
I use this code for push and pop view controllers:
push:
[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];
pop:
[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];
.. and it works fine for me.
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
I think what they mean "directly" is by hooking things up just the same way as the xcode "Navigation Application" template does, which sets the UINavigationController as the sole subview of the application's UIWindow.
Using that template is the only way I've been able to get the Will/Did/Appear/Disappear methods called on the object ViewControllers upon push/pops of those controllers in the UINavigationController. None of the other solutions in the answers here worked for me, including implementing them in the RootController and passing them through to the (child) NavigationController. Those functions (will/did/appear/disappear) were only called in my RootController upon showing/hiding the top-level VCs, my "login" and navigationVCs, not the sub-VCs in the navigation controller, so I had no opportunity to "pass them through" to the Nav VC.
I ended up using the UINavigationController's delegate functionality to look for the particular transitions that required follow-up functionality in my app, and that works, but it requires a bit more work in order to get both the disappear and appear functionality "simulated".
Also it's a matter of principle to get it to work after banging my head against this problem for hours today. Any working code snippets using a custom RootController and a child navigation VC would be much appreciated.
In case this helps anyone. I had a similar problem where my ViewWillAppear is not firing on a UITableViewController. After a lot of playing around, I realized that the problem was that the UINavigationController that is controlling my UITableView is not on the root view. Once I fix that, it is now working like a champ.
I just had this problem myself and it took me 3 full hours (2 of which googling) to fix it.
What turned out to help was to simply delete the app from the device/simulator, clean and then run again.
Hope that helps
[self.navigationController setDelegate:self];
Set the delegate to the root view controller.
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)
}
I'm not sure this is the same problem that I solved.
In some occasions, method doesn't executed with normal way such as "[self methodOne]".
Try
- (void)viewWillAppear:(BOOL)animated
{
[self performSelector:#selector(methodOne)
withObject:nil afterDelay:0];
}
You should only have 1 UIViewController active at any time. Any subviews you want to manipulate should be exactly that - subVIEWS - i.e. UIView.
I use a simlple technique for managing my view hierarchy and have yet to run into a problem since I started doing things this way. There are 2 key points:
a single UIViewController should be used to manage "a screen's worth"
of your app
use UINavigationController for changing views
What do I mean by "a screen's worth"? It's a bit vague on purpose, but generally it's a feature or section of your app. If you've got a few screens with the same background image but different overlays/popups etc., that should be 1 view controller and several child views. You should never find yourself working with 2 view controllers. Note you can still instantiate a UIView in one view controller and add it as a subview of another view controller if you want certain areas of the screen to be shown in multiple view controllers.
As for UINavigationController - this is your best friend! Turn off the navigation bar and specify NO for animated, and you have an excellent way of switching screens on demand. You can push and pop view controllers if they're in a hierarchy, or you can prepare an array of view controllers (including an array containing a single VC) and set it to be the view stack using setViewControllers. This gives you total freedom to change VC's, while gaining all the advantages of working within Apple's expected model and getting all events etc. fired properly.
Here's what I do every time when I start an app:
start from a window-based app
add a UINavigationController as the window's rootViewController
add whatever I want my first UIViewController to be as the rootViewController of the nav
controller
(note starting from window-based is just a personal preference - I like to construct things myself so I know exactly how they are built. It should work fine with view-based template)
All events fire correctly and basically life is good. You can then spend all your time writing the important bits of your app and not messing about trying to manually hack view hierarchies into shape.