Best practice for presenting UITabBarControllers - swift

I'm working on a project that has two different sets of tabs that are presented based on certain conditions. My question is how to best present the two different sets of tabs via their UITabBarControllers.
Right now, the app is meant to launch with the default UITabBarController but when I want to switch, I'm confused as to how to best present the second UITabBarController and completely get the first UITabBarController off the memory stack. And, vise versa. Would it be the same to switch back to the first UITabBarController?
This is the code used as of right now to switch from the first to the second.
let secondaryTabBarController = SecondaryTabBarController()
let secondaryTabs = UINavigationController(rootViewController: secondaryTabBarController)
UIApplication.shared.keyWindow?.rootViewController = secondaryTabs

To address your concern about memory, the method you suggested is completely fine in that regards and does not inherently cause any memory leaks.
And yes, if you want to switch back to the first tab bar controller you can use the same method, creating a new instance of your first tab bar controller and setting it as the window's root view controller.
You can animate the transition by using UIView.transition(with:duration:options:animations:completion:), which has some built-in transition animations.
Alternatively you can use setViewControllers(viewControllers:animated:) on UITabBarController if you just want to change the tabs, or if you want to preserve selection.

Related

Adding a Monotouch.Dialog to a standard view

I have a standard view with a bar at the top for navigation. I also have a Monotouch.Dialog set in it's own source file. I've looked around for a solution to this, but can't seem to find a definitive answer on how to add a MTD to a normal view.
Is there a simple way to do this?
You instantiate the DialogViewController and add its View to your view.
DialogViewController vc = new DialogViewController(null);
// Build and set your root here.
vc.View.Frame = new RectangleF(20f, 20f, 280f, 560f);
this.View.AddSubview(vc.View);
You might have issues with ViewController methods (i.e. rotation methods) not being forwarded correctly in this scenario, so be sure to test.
This is extremely ugly though and should only be used when you absolutely must have the Dialog view nested.
In a scenario where the DialogViewController is displayed in full screen (with or without the navigation bar), a more elegant solution is to use a UINavigationController as the root view controller in your app (which would take care of the navigation bar for you), and either setting or pushing the newly created DialogViewController onto it.

How do I switch ViewController instead of adding to stack?

I have a number of objects linking to each other in a circle. Each object holds a reference to it's neighbors, square and triangle are different class types:
The tow classes, triangle and square, are made visible with a ViewController, and they link to each other with segues.
So far, no problem. However, while I'm browsing around in my structure, I keep adding ViewControllers on top of each other. Not only does this seem a bad practice memory-wise, but it also presents the problem that when I want to quit this structure, I have to back-track by closing all ViewControllers that I opened.
So what I'm looking for, is a way to not add the next ViewController on top of the current on in the stack, but to replace the current ViewController with the next one.
I've been looking for a while for a solution, but have little success. So I feel that doing what I want is either impossible, or I'm just not getting an obvious point and don't know what to look for. Do I need a RootViewController for something like this? Or should I create a custom segue that dismisses the old ViewController before adding the new one? I'm really at a loss here.
Add all subView once , in viewDidLoad and give tags to all you SubView after that where you you want to show that view in viewController don't add it just bring it to front by calling the function [[self.view viewWithTag:1]bringToFront]
Since you are probably using a navigationcontroller, you should have a look at the UINavigationController reference. There are methods to modify the navigation stack. You cannot do this only with a storyboard. You will need some custom code.
You should have a look at the UINavigationController method setViewControllers:animated:.
Sounds like you want to do one of a couple things
Replace your rootViewController
Have a rootViewController which acts as a container for a single UIViewController and change that out as needed. In iOS 5 you can do this with a custom UIViewController, but or you could use one which Apple provided.UINavigationController` can do it, but unless you are also using it to navigate a tree like structure of view controllers it's probably not the best option.
Your best answer sort of relies on your need.
If your controllers don't have much state or don't get swapped in and out a lot you could use option 1.
If you expect users to swap between controllers often and quickly and/or your controllers require significant setup or have a lot of state then you might want to a NSArray and just use presentViewController:animated:completion: to show different controllers when needed. Storing your controllers in a NSArray has the added bonus of easily being able to identify their neighbors.
The UINavigation controler's method setViewControllers is an option.
Another would be to pop the most rencent view controller using popViewControllerAnimated:
In some cases popToRootViewControllerAnimated: would be best or even popToViewController:animated:. Hoever, I personally was not successful using popToViewController:animated: but that may have been my fault at that time.
Yes, I think you need a root view controller. I myself tried to exchange the root view controller the other day but failed doing so. In the end it was probably not the most elegant solution but easier for me to implement some dummy root view controller which does nothting but display my app logo in the background (Same as the default image but moved into negative coordinates in order to match the default image on startup. It is laying 'behind' the navigation bar and status bar.). It could show some empty black background or so. In the end it is will most probably never be visible.

Is it bad practice to create unique view controllers for different tabs that do essentially the same thing?

Ok so basically I have a UITabBarController as my root view controller. I have three tabs that will all have UINavigationController objects nested in them, controlling three table views each.
Each mode will access the same database in the same way, but just sort by different variables. Very similar to the way the iPod app works - whether you narrow down your search by Artist or Genre, you end up at the same "detail view" (the song playing).
My question is, should I link all three tabs in Interface Builder to the same UINavigationController, but just populate the table depending on the selected tab? Or should I create completely independent objects for each tab, and copy and paste code?
The first way seems more efficient and flexible, but the second seems like it will be a little more explicit and easy to read!
Thanks for any help :)
I think clearing the navigation controller stack on every tab switch (assuming it is not hidden when the non-uppermost navigation child is shown) would be much more resource-consuming than having all three/four UINavigationControllers available all the time (mostly for quick tab-switching).
Further, if the owning UINavigationController is the only object that retained (owns) the UIViewControllers on the stack, then you will also deallocate your UIViewControllers should you decide to reset the navigation stack (1-Nav scenario). Assuming of course they are not "statically" present inside a NIB.
TL;DR version
I'd use a separate UINavigationController for each tab, in a low memory-footprint app it will increase the visual performance of your tabs.

How do I switch between Navigation Controllers?

Situation:
I have an Xcode project based on the "Navigation-Based-Application" template. So that means I have a SINGLE UINavigationController that manages a UIViewController.
What I want To Do:
What I want to do is add one more UINavigationController to my project -- and be able to switch back and forth between them. (I want to do this to make space for some seperate unrelated content so that it does not have a back button pointing back to the root view controller.)
Question:
How do I add one more UINavigationController to my project and switch between the two UINavigationControllers?
The most common, and natural iPhone OS, way of doing this is to add a UITabBarController to your application. The Xcode template Tab Bar Application will guide you in the right direction on how to use it.
But...
If you don't like to have a Tab Bar in your application, and wish to switch between different UINavigationController instances (or any UIViewController for that matter), you can do something like this.
First you need to create your UINavigationController instances in a appropriate place (for example a new view controller, or in you Application Delegate, if you want to take the easy way out). You can then switch between controllers by just swapping which Navigation Controller's view that should be visible.
Example in the Application Delegate, "firstNavigationController" and "secondNavigationController" are UINavigationController instance variables:
- (void)showFirstNavigationController {
[secondNavigationController.view removeFromSuperview];
[self.window addSubview:firstNavigationController.view];
}
This will simply display the first instead of the second Navigation Controller. Note that this example is very simple. I didn't take into consideration that you should correctly handle the methods viewWillAppear:, viewDidAppear: and so on.

TabBar Controller question

I have an app that has four tabbar controllers views in it. When the app starts up, all four are loaded via SQL select statements. How do I tell it not to load these controllers at startup, but to do it when I select a value from the first screen?
thx
wes
I'm assuming you have 4 ViewController placed into a single TabBarController. If this is the case, why do you want to defer loading? The actual views (usually the 'heavy' part of the ViewController) are not loaded until you actually select one in the tab bar to bring it forward (which is, I think, the behavior you're looking for).
The whole point of the UIViewController class (well, one of the points, anyway) is to allow you to place your view in a hierarchy without having to create all the UI elements required until it's actually time to show it. This makes app organizations much easier.
make simple UIViewController in tabbar, but when tab is selected make loading