Tab bar disappeared when back to initial view controller - swift

i have 2 view controllers then tab bar controller connected to 3 navigation controller , each navigation connected to multiple views .
The point that from one of these views that is connected to one of navigation controllers , i want to back again to the start screen , it good by this 2 lines :
let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController")
UIApplication.shared.keyWindow?.rootViewController = loginViewController
but after i do this and want to navigate again to the tab bar its disappeared from the view . I used this to navigate to tab bar :
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let viewTabController = self.storyboard?.instantiateViewController(withIdentifier :"MainTabBarController") as! MainTabBarController
viewTabController.selectedIndex = 1
appDelegate.window?.rootViewController = viewTabController
Thanks in advance.

When you use instantiateViewController you are making new instances of view controllers in memory while there is no need in your case , you have created them before. so you can dissmis your tabBar and go back to first screen like this (initial viewcontroller must be embeded into a navigation controller) :
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let navigationController = appDelegate.window?.rootViewController as! UINavigationController
navigationController.dismiss(animated: true, completion: nil)
for bringing back tabBar you can either save its instance in your app delegate and present it or use a storyboard segue to present it modally
:)

Related

Present viewcontroller with tabbar

I created UITabBarController programmatically in AppDelegate with 4 view controllers(using .xib). When user tap some button on ViewController (VC-A) it present another VC (VC-B) and covered tabbar. So I want to VC-B has a tabbar on the button.
I tried to add VC-B as a child of tabbarcontroller. I tried to .present(vc) and .show(vc) on both: VC-A and VC-A.TabBarController
Creating controllers in AppDelegate:
let controllers = [tabViewController1,tabViewController2,tabViewController3,tabViewController4]
tabBarController.viewControllers = controllers
window?.rootViewController = tabBarController
presenting in VC-A
self.tabBarController?.present(controller, animated: false, completion: nil)
right click and drag from tabbar controller in storyboard to VC-B. that should create a tab on the bottom of your VC-A and VC-B to go back and forth without having to implement any backend code unless you want to animate
The solution is to embed every VC in navigationController and then add to TabBarController.
let vc1 = ViewController1()
let navController1 = UINavigationController(rootViewController: vc1)
navController.isNavigationBarHidden = true
let controllers = [navController1, navController2, navController3, navController4]
tabBarController.viewControllers = controllers
window?.rootViewController = tabBarController
Then call
self.navigationController?.pushViewController(controller, animated:
true)
To diplay VC with tabbar
I will press the red login button at the bottom of the picture and try to log in.
login button => "로그인"
After that, log in.
let moreVC = self.storyboard?.instantiateViewController(withIdentifier: "MoreViewController") as! MoreViewController
moreVC.definesPresentationContext = true
moreVC.modalPresentationStyle = .fullScreen
let navController = UINavigationController(rootViewController: moreVC)
self.present(navController, animated: true, completion: nil)
If the login proceeds without error, the above code will be called to display the screen when the login is completed.
If the flow proceeds as the code above, this screen appears.
The screen shown is not fullscreen, and the tabbar at the bottom is gone. The screen I want is the screen below.
How can I present a tab bar when presenting the screen?

how can I move a data array between tab bar viewControllers when I have navigationControllers involved

I have a tab bar controller and 3 viewControllers connected to it and when I move data between the viewControllers I use the following code, which works perfect:
let secondTab = tabBarController?.viewControllers![1] as! ImageViewController
secondTab.imageArray = images
Now I added navigation to the second viewController with EDITOR->Embed In....so, there is now a navigationController between my ImageViewController and the tabBarController. How can I still get the data to the ImageViewController?
You can try
if let nav = tabBarController?.viewControllers![1] as? UINavigationController {
if let let secondTab = nav.topViewController as? ImageViewController
secondTab.imageArray = images
}
}

Swift -injecting vars in ViewControllers

I am proudly new to iOS developing and I am trying to build my first app. I am doing a course on an online platform which does the following in the
AppDelegate -> application didFinishLaunchingWithOptions:
let navigationController = window?.rootViewController as! UINavigationController
let notebooksListViewController = navigationController.topViewController as! NotebooksListViewController
notebooksListViewController.dataController = dataController
This app has a Navigation controller which begins with an UIViewController.
I have 2 questions here, first is why this works, I mean, I am in AppDelegate, so the NotebooksListViewController (first view of the app) is not instantiated yet (I think), so why I am able to inject a variable in it?
On the other hand, the second question, is how can I do this in a different scene? I have a TabBarViewController as first scene, and the first tab is a UITableViewController and I want to inject the same way my dataController var, how can I accomplish this? I could not get to do it, neither understand it.
Thanks in advance.
It works, because of some Xcode magic:
In your Target Setting, General tab, the Main Interface entry specifies the name of the Storyboard to be loaded automatically when your app starts up:
In the storyboard, the Initial View Controller then will be instantiated. It seems like this is an UINavigationController.
Since this is done automatically, it just works - until you want to do something special :-)
If you want to start up with a different scene - maybe from a different view controller - you could just change either the Main Interface to another storyboard, the Initial View Controller (inside the storyboard) or both.
Or, you could just start up by yourself, by leaving the Main Interface empty and create your own view controller inside the app delegate (didFinishLaunchingWithOptions), something like
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let tabVC = mainStoryboard.instantiateViewControllerWithIdentifier("TabCtrl") as? UITabBarController {
self.window?.rootViewController = tabVC
// Access the subcontrollers, or create them
// Initialize their values
// tabVC.viewControllers[0].data = ...
} else {
// Ooops
}
self.window?.makeKeyAndVisible()
Answer to your first question
as the method name is self explanatory didFinishLaunchingWithOptions means your application is didfinish with launching with options and its about to enter in foreground so here application need to set rootViewController so in this method controller you want to set as view controller is initiated thats why you can inject variable in it
answer to second question
let navigationController = window?.rootViewController as! UITabbarController
let VC = navigationController.childViewController
//Now Using VC you can access all you controller of tabbar controller
let notebooksListViewController = navigationController.topViewController as!
NotebooksListViewController
notebooksListViewController.dataController = dataController
now as shown above you can use VC to access you view controllers
but be careful here because VC return viewcontroller array so you need make checks for perticular VC you want to access

navigationController is nil in swift

I have two storyboard (Main and SB2)
I have one view controller in storyboard in Main and one in SB2
I perform
let SB2 = UIStoryboard(name: "SB2", bundle:nil)
let vc : UIViewController = self.SB2.instantiateViewControllerWithIdentifier("VC2")
self.showViewController(vc, sender: self)
After the second viewcontroller loads and this command is run, it prints nil:
print(self.navigationController) // prints nil
In SB2 (second storyboard) I clicked on the viewcontroller (VC2) and then clicked on Editor > Embed In > Navigation Controller. This placed a navigation controller with the storyboard and the root view controller is VC2. I triple checked this. The first sign of it being connected was the gray navigation bar on top. The second being that there is segue connecting the navigation controller to VC2 and the last place I could have checked is in the navigation controller utilities.
I am thinking that maybe I shouldn't transition from VC1 to VC2 directly but rather VC1 to NavigationController however I don't know how to do this or if its even possible.
I don't know when sb2 prints nil when in face a navigation controller is connected to it. Any help is appreciated.
You need to push the view controller (VC2) on to the navigation controller.
let SB2 = UIStoryboard(name: "SB2", bundle:nil)v
let nvc = SB2.instantiateViewControllerWithIdentifier("NVC") as! UINavigationController
let vc : UIViewController = self.SB2.instantiateViewControllerWithIdentifier("VC2")
nvc.pushViewController(vc, animated: true)
Then in your view controller try calling
self.navigationController
In your storyboard,
select the initial ViewController. With this view controller selected, choose the menu item
Editor -> Embed In -> Navigation Controller

UISplitview: access UITabBarController from appDelegate

I need to access the UITabBarController, and the second of its subviews from the appDelegate.
This is what I have tried in applicationDidEnterBackground:
let splitViewController = self.window!.rootViewController as! UISplitViewController
let leftNavController = splitViewController.viewControllers.first as! UINavigationController
let tabController = leftNavController.tabBarController! as UITabBarController
let controllers : Array = tabController.viewControllers!
print("viewcontrollers \(controllers)")
The app crashes, complaining that tabController is nil. If i remove the UINavigation controller from storyboard, the UITabBarController is accessed easily with:
let tabController = splitViewController.viewControllers.first as! UITabBarController
What is the correct way to access the childcontrollers of the UITabBarController, where a UISplitView is the root?
Finally I found a solution. I had to use "childViewControllers" of the navigation controller like this:
let splitViewController = self.window!.rootViewController as! UISplitViewController
let leftNavController = splitViewController.viewControllers.first as! UINavigationController
let tabController = leftNavController.childViewControllers.first as! UITabBarController
let viewControllers : Array = tabController.viewControllers!
print("viewControllers \(viewControllers)")
Now I can easily access any of the viewControllers and run their methods from appDelegate :-)
Rather than embedding your tab bar controller in a navigation controller, you should embed the child view controllers in their own navigation controllers, like this:
Split View -> Tab Bar -> Navigation Controller #1 -> View Controller
-> Navigation Controller #2 -> View Controller
This is the correct way to use a tab bar in conjunction with a navigation controller.