Creating a TabBarControllerDelegate in a Storyboard - iphone

I'm having difficulty creating a UITabBarControllerDelegate in my Storyboard driven iOS5 application. Here is the situation:
I have an initial screen that will eventually handle login but which currently just has a button that sends the user to...
...a Tab Bar Controller with five tabs. Each of these tabs go to...
...a Navigation Controller with many child View Controllers under the root.
(If it helps, a screenshot of the relevant Storyboard section is here.)
When the user switches tabs, I always want the user to be directed to the Root View Controller for that particular Navigation Controller, and not the most recently visited View Controller (which is the default behavior).
I understand that to do so, I need to call popToRootViewControllerAnimated when a Tab is pressed as discussed here and here, but I can't figure out how to do that within the storyboard. How can I do this without scrapping the storyboard and starting over?
Thanks!

There are more than one solutions to your problem (its a matter of design pattern decision). Some of them could be:
Subclass UITabBarController and set it as the custom class of your tabbar in your storyboard (also connect the delegate to your object in order to be handled) and override the -tabBarController:didSelectViewController: delegate method
Pop to the root by calling -popToRootViewControllerAnimated from the viewWillDisappear event of every view that you want this behavior implemented

You can create your own TabBarController, implement a method that instantiate your view controllers
-(UIViewController*) viewControllerWithTabTitle:(NSString*) title
viewController(NSString *)viewController {
UIViewController* returnViewController = [self.storyboard
instantiateViewControllerWithIdentifier:viewController];
return returnViewController;
}
Then in the viewDidLoad method you create the array with the view controllers, that in your case would be the NavigationController's identifier that you set on the InterfaceBuilder.
- (void)viewDidLoad {
self.viewControllers=
[NSArray arrayWithObjects:
[self viewControllerWithTabTitle:#"Option 1" viewController:#"viewController1"],
[self viewControllerWithTabTitle:#"Option 2" viewController:#"viewController2"],
[self viewControllerWithTabTitle:#"Option 3" viewController:#"viewController3"],
[self viewControllerWithTabTitle:#"Option 4" viewController:#"viewController4"],
[self viewControllerWithTabTitle:#"Option 5" viewController:#"viewController5"], nil];
}

Related

NavigationController and Modal Views

I am a newbie to iOS world and have started building custom code on top of a templated code.
So excuse me for the obvious.
The View chain starts with a MainWindow.xib which contains a App Delegate Object, a Window Object and Application ViewController. I dont understand why those objects are needed over there. But what I understand, I need to mention starting ViewController in the "Nib Name" Property to initiate my custom View Controller (called "EmptyViewController"). Its a dummy view controller, just there to avoid crash to happen as a result of missing valid viewcontroller.
I initiate a separate Modal View Controller(MainViewController) inside didFinishLaunchingWithOptions.
Code for initiating modal View Controller --
self.window.rootViewController = self.viewController;
mainView = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
// present the viewcontroller
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:mainView];
[self.viewController presentModalViewController:navController animated:NO];
// release it, because it's retained as modalViewController
[navController release];
I do not put this MainViewController inside MainWindow.xib as I want to have navigation at the root of MainViewController.
Inside MainViewController, I push HelpViewController when "help" button is pressed.
But HelpViewController does not show any navigation bar. I do not understand why?
Code for Pushing Navigation bar --
HelpViewController *helpVC = [[HelpViewController alloc] init];
[self.navigationController pushViewController:helpVC animated:YES];
[helpVC release];
So I would like to understand --
1) Why is MainWindow.xib needed? Can I remove it? (Note: I tried to remove it, but then I get blank screen)
1.a) Why are all the controls/objects App Delegate Object, a Window Object and Application ViewController objects needed?
2) Why doesnt HelpViewController show Navigation bar?
3) Another thing I noticed, if I say self.presentingViewController, EmptyViewController handle is returned while popViewController returns me back to MainViewController.
Thanks
The App Delegate simply implements some app-level 'callbacks' by which iOS communicates with your own code. In main.m you can see how iOS is told which of your classes implements UIApplicationDelegate. iOS creates an instance of this class and call these delegate methods ('callback') whenever appropriate (e.g. when the app goes to background).
The Window is something iOS provides, your app needs to tell what to display on it. And, as you saw, this is usually done in didFinishLaunchingWithOptions (which is called by iOS to inform your app things are ready to get started).
A View Controller is a class that handles states of stuff you show on the Window. You don't show stuff directly on the Window, but instead use Views. Every View Controller has a View with UI elements.
The XIB or NIB is a UI description/layout file. A XIB and View are linked together; you need to tell the XIB to which View Controller member (e.g. a UILabel) a UI element belongs, and you tell the XIB which View Controller method to call on a certain UI event (e.g. user taps on a button).
These are the basics. I'm aware it does not answer all your questions; I suggest you read the very good Apple documentation. Don't try to understand everything immediately as things, as you're experiencing, indeed can seem illogical at start.

viewwillappear and viewdidappear not called

this question is very frequent, but I am not able to solve it with any answers available.
I am working on iOS 5.1. My navigation controller is one tab amongst tab bar view controllers. There's a tableview, in which selecting of a row pushes new view controllers.
This problem occurs Only on selecting of the second row and only sometimes. It's not regular.
The Pushed view comes blank - viewWillAppear/viewDidAppear are not being called. On clicking the back button of the navigation bar - the root view's viewWillAppear/viewDidAppear are also not being called, making it blank.
I am pushing the view on select of first row/second row in exactly the same way. But the problem occurs only on the second row.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
switch (indexPath.row) {
case 0:
AViewController *aObj = [[AViewController alloc] init];
aObj.homeObj = self;
[self.navigationController pushViewController:aObj animated:YES];
[aObj release];
break;
case 1:
BViewController *bVCObj = [[BViewController alloc] init];
bVCObj.homeObj = self;
[self.navigationController pushViewController:bVCObj animated:YES];
[bVCObj release];
break;
default:
break;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I have tried this and this but in vain.
viewDidLoad is being called on pushing the BViewController, However, viewWillAppear and viewDidAppear is not being called. Following is my viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
NSLog(#"nav stack: %#", [self.navigationController viewControllers]);
NSLog(#"nav stack: %#", [[self.navigationController visibleViewController] description]);
//some initialization and call of methods
}
It's not regular. Sometimes I get this scenario, and this continues until I close the app from the background and restart it. But sometimes it works just fine. I am just pushing my view controller to the nab stack.
As I mentioned in the comment, It's a regular navigation controller in tab bar controller.
How are you defining your views for AViewController and BViewController? Generally you'd use initWithNibName, e.g.
AViewController *aObj = [[AViewController alloc] initWithNibName:#"mynibname" bundle:nil]`
As Carl pointed out, you can apparently use just init (though I don't see this documented in the UIViewController Class Reference), but then the system will be very particular about the name of your NIB file. The documentation does say, though, that you can use initWithNibName and pass a nil for the NIB name, in which case it will try to find it for you. Personally, if you're having inconsistent results, though, I'd try using initWithNibName and explicitly pass the name of your NIB, and see if that rectifies the situation.
Or are you building your view programmatically with loadView in your two controllers? Then you need to show us those loadView routines (not to be confused with viewDidLoad).
But according to the documentation, you need to either specify your NIB or use loadView. See the View Management discussion in the UIViewController Class Reference.
Update:
Given your feedback, I have a couple of thoughts:
Needless to say, the problem is apparently not related to the above code. You need to broaden you search and show us more code. Perhaps show us your viewDidLoad of B?
Generally when you don't get these sorts of events, it's because the view controller hierarchy has gotten out of sync with the view hierarchy. The most common way that people do this is if they've done something like "[addSubview someNewController.view]" at some point. If you're using a view controller in any context either than (a) your app delegate's initial configuration; (b) presentViewController (or dismiss); or (c) pushViewController (or pop), then you might want to share what you've done.
As andreamazz pointed out, your comment, "My navigation controller is inside a view controller of the tab bar controller," is a little disturbing if one reads it literally. You can put navigation bar in a view controller's view, but you can't put a navigation controller in a view controller (unless you're doing view controller containment, which is a whole different beast). Equally concerning is where, in another one of your questions, you said, "Embedding a UINavigationController or UITabBarController (my case) in a UIViewController somehow interrupts with the calling of these methods." Thing is, you don't embed nav controllers in other view controllers (unless it is, itself, a container controller such as a tab view controller), but rather its the other way around. But if you literally mean that you have a controller that contains a nav controller, you have to show us how you're doing that (proper view controller containment?) because that's highly unusual.
It's unusual, but I've had projects get corrupted, ending up in weird states. At a minimum, I might suggest "Product" - "Clean" and rebuild. If problem persists, and you've isolated the problem to to B's NIB, then temporarily rename the it and build a quick and dirty one from scratch.

Navigation based application with an add button

I created a new Navigation Based Application project.Then in MainWindow.xib I added a button to the navigationbar. I would like to push a new View onto the screen where I can enter information, which will be added as an object to the array of the UITableView.
But I don't know where to write the IBAction to link the button to (Appdelegate or the RootViewController)? Because as you see in the screenshot, it resides in MainWindow.xib because the RootViewController is merely a Table and doesn't contain the navigation. But in the document view of MainWindow.xib it is located under the RootViewController.
Do I have to create a new View Controller inside the XIB as well and create an IBOutlet for it?
I tried putting the code inside my AppDelegate and reference the button to the delegate but it doesn't work.
Please help. Thanks in advance.
See the screenshot here: http://i56.tinypic.com/5djbcm.png
When you ask yourself a question "where does this action belong" it's most probably a controller because controllers handle event flows in your app. Next question - "What controller is in charge when this action happens? What controller is most interested in this action?". Answer in your case is root table controller (RootViewController instance). Create an IBAction method in it which will push form controller (one you use to enter information) to navigation controller.
// somewhere in RootViewController.m
- (IBAction)addNewEntry {
NewEntryFormController *c = [[[NewEntryFormController alloc] init] autorelease];
// ...
[self.navigationController pushViewController:c animated:YES];
}

Is parentViewController always a Navigation controller?

I was kind of scratching my head at this a week ago, and now with a little bit more Cocoa experience under my belt I feel like I have an inkling as to what might be going on.
I'm making an application that is driven by a UINavigationController. In the AppDelegate, I create an instance of this class, using "page 1" as the Root View Controller.
UINavigationController *aNavigationController = [[UINavigationController alloc]
initWithRootViewController:page1ViewController];
Now here's where I'm having the problem. From "page 1" I'd like to use a modal view controller that slides over the interface and then disappears once the user has made an edit. I do that using code like this, inside of Page1ViewController:
[self presentModalViewController:myModalViewController animated:YES];
When the Modal View Controller is gone, I want a value on "Page 1" to change based on what the user entered in the Modal View Controller. So, I wrote some code like this, which resides in the Modal View Controller:
[self.parentViewController dismissModalViewControllerAnimated:YES];
[self.parentViewController doSomethingPleaseWithSomeData:someData];
The update to page 1 wasn't happening, and it took me a long time to realize that the "doSomethingPleaseWithSomeData" message was not being sent to Page1ViewController, but the Navigation Controller.
Is this always to be expected when using Navigation Controllers? Did I perhaps configure something improperly? Is there an easy way to get at the View Controller that I want (in this case, Page1ViewController).
I would recommend using the delegation pattern to solve your problem. Create a property
#property (nonatomic, assign) id <MyModalViewDelegate> delegate;
And a corresponding protocol
#protocol MyModalViewDelegate
#optional
- (void)myModalViewControllerDidFinish:(MyModalViewController *)aModalViewController;
#end
When the user finishes with your view (e.g. taps the save button), send this message:
if ([self.delegate respondsToSelector:#selector(myModalViewControllerDidFinish:)])
[self.delegate myModalViewControllerDidFinish:self];
Now, set the delegate to the view controller that should manage the whole thing, and it will be notified when the view controller is finished. Note that you'll need your view controller to dismiss the modal view controller. But, logically, that makes sense, since it was the object that presented the modal view controller in the first place.
This is how Apple solves this problem in, for example, the UIImagePickerController and UIPersonPickerController.
There are a couple of ways you can handle this. The simplest is probably just to add a UIViewController property into myModalViewController and set it to page1Controller before you present it:
myModalViewController.logicalParent = self; //page1Controller
[self presentModalViewController:myModalViewController animated:YES];
Just make sure you add the appropriate instance variable #property, and #synthesize for logicalParent to myModalViewController, then you will have a way to communicate data back to the ViewController that triggered the modal dialog. This is also for passing data back and forth between different levels of navigation before you push and pop them on the stack.
The one important thing to worry about when doing this is that it is easy to get retain loops if you are not careful. Depending on exactly how you structure this you might need to use assign properties.
I just ran into this same problem. It definitely seems that if you put a UIViewController embedded in a NavigationController, then when, from that UIViewController you present another UIViewController modally, the presentee thinks that the presenter is the NavigationController. In other words, parentViewController is incorrect.
I bet this is a bug: either that, or the documentation seems incomplete. I will inquire.
Just ran into the same problem. I believe this is a bug. My scenario is the following:
A navigation hierarchy with A, B and C view controllers in this order. On C there's a button that would open a modal view controller called D. Once D is presented the navigation controller drops C from its hierarchy which is a terrible behavior. Once D gets dismissed, the navigation controller instantiates a new C type view controller and pushes it into its hierarchy to recover the original one. Terrible. My solution is hacking the navigation hierarchy this way (a very bad solution but works well. with a 2 dimension array you could implement stacking modals):
- (void)presentModalViewController:(UIViewController *)c {
[self.navigationHierarchy removeAllObjects];
[self.navigationHierarchy addObjectsFromArray:[navigation viewControllers]];
[navigation setViewControllers:[NSArray array] animated:YES];
[navigation presentModalViewController:c animated:YES];
}
- (void)dismissModalViewController {
[navigation dismissModalViewControllerAnimated:YES];
[navigation setViewControllers:[NSArray arrayWithArray:self.navigationHierarchy] animated:YES];
}
These two methods are defined where I maintain the main navigation hiererchy: the app delegate. navigation and navigationhierarchy are defined this way:
NSMutableArray *navigationHierarchy;
UINavigationController *navigation;

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.