Embedding Navigation Controller into Tab Bar Controller - ios

I currently have a DetailViewController segued from a ViewController, which is embedded in a UINavigationViewController, which I want to embed in a UITabBarController. When I first did it on my storyboard, my app crashed with the error:
"Could not cast value of type 'UITabBarController' (0x10badf258) to 'UINavigationController' (0x10badf208)".
After research, I added the first two lines (let tabVc =, and let navVc = ) and still crashed. What am I missing to create a successful TabBarController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let tabVc = segue.destinationViewController as! UITabBarController
let navVc = tabVc.viewControllers!.first as! UINavigationController
if segue.identifier == "ShowItem" {
if let row = tableView.indexPathForSelectedRow?.row {
let item = itemStore.allItems[row]
let detailViewController = segue.destinationViewController as! DetailViewController
detailViewController.item = item
detailViewController.imageStore = imageStore
}
}
}
UPDATE: After applying changes, my error has changed to
"Could not cast value of type 'UITabBarController' (0x103ff6258) to 'Photomania.ItemsViewController' (0x1029520d0)."
Error

I think you are approaching the problem in a wrong way. You can set the imageStore and itemStore of ItemsViewController in it's viewDidLoad.
override func viewDidLoad() {
super.viewDidLoad()
self.itemStore = ItemStore()
self.imageStore = ImageStore()
}
But if you wish to do it in didFinishLaunchingWithOptions of AppDelegate then this is how you would do it.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let rootController = window?.rootViewController
if rootController is UITabBarController {
let firstTabItem = (rootController as! UITabBarController).viewControllers?[0]
if firstTabItem is UINavigationController {
let firstController = (firstTabItem as! UINavigationController).viewControllers.first as! ItemsViewController
firstController.itemStore = ItemStore()
firstController.imageStore = ImageStore()
}
}
}

As the error clearly states, it's this line of code that is failing:
let navVc = tabVc.viewControllers!.first as! UINavigationController
according to the error the first viewController in the tabVC is not a navigationVC.
So make sure your tab bars are arranged in the correct order and be certain that the first viewController of your tabVC is indeed a navigation view controller.

Related

Show viewcontroller by storyboard id inside UITabBarController

I am trying to show a specific viewcontroller, inside my UITabBarController by using the viewcontrollers storyboard id.
I can only get the viewcontroller to be shown without the UITabBarController.
How do I also show the UITabBarController?
I have tried this:
let identifier = "stats_view"
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: identifier)
window?.rootViewController = vc
Which gave me the problem listed above.
try the following code.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if let myTabBar = self.window.rootViewController as? UITabBarController { // Getting Tab Bar
myTabBar.selectedIndex = 2 //Selecting tab here
return true
}
}
You should set selectedIndex of tabBarController to view specific viewController which are embedded in tabBarController. Use following code.
self.tabBarController?.selectedIndex = 1

Set UITabBarController as rootViewController

I have a UITabBarController and I want to show this screen and not the login screen if the user session is still active.
My UITabBarController has 3 ViewControllers and the problem is that I don't see the TabBar links in the bottom and I'm unable to navigate.
Without the following code everything works fine. I mean after login I can navigate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
if Auth.auth().currentUser != nil {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = HomeTabBarController()
}
return true
}
I have also tried the following code to set the rootViewController but it's the same problem.
When I try to set one of the other view controllers as root (one of the children), the Tab Bar doesn't show at all
var rootView: MyRootViewController = MyRootViewController()
if let window = self.window{
window.rootViewController = rootView
}
What am I doing wrong here?
I was facing same issue and I came across your post, the problem with your code is that HomeTabBarController() is creating a whole new TabBarController so to fix it try the following approach I used.
if Auth.auth().currentUser != nil {
print("******************************User Present******************************")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Interface Builder -> Identitiy Inspector -> Storyboard ID
// Set up the Tab Bar Controller to have two tabs
let tabBarController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
}
Edit Make sure to add the Identifier to your TabBarController
// Interface Builder -> Identitiy Inspector -> Storyboard ID
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//// this code changes the initial point of aap///////
window = UIWindow(frame: UIScreen.main.bounds)
let nav = UINavigationController()
let myview = SettingTabbar()
nav.viewControllers = [myview]
window?.rootViewController = nav
window?.makeKeyAndVisible()
return true
}
And Function SettingTabbar is:
func SettingTabbar()->(UITabBarController)
{
//Setting TabBar
let tabbar = UITabBarController()
//Designing Tabbar Item Images
let table = UITabBarItem(title: nil, image:UIImage(named: "002-list") , tag: 0)
let collection = UITabBarItem(title: nil, image: UIImage(named: "001-collect"), tag: 1)
let insert = UITabBarItem(title: nil, image: UIImage(named: "add"), tag: 2)
//Getting TabBar ViewControllers
let TableView = newViewController()
let CollectionView = PersonCollectionViewController()
let InsertRec = nextViewController()
//Setting ViewControllers on TabBar Items
TableView.tabBarItem = table
CollectionView.tabBarItem = collection
InsertRec.tabBarItem = insert
let controllers = [TableView,CollectionView,InsertRec]
tabbar.viewControllers = controllers
tabbar.viewControllers = controllers.map{UINavigationController(rootViewController: $0)}
//Setting Title
tabbar.navigationItem.title = "Person Record"
return tabbar
}
The problem is this line:
window?.rootViewController = HomeTabBarController()
That is the wrong HomeTabBarController. It is a totally new HomeTabBarController with no children. You need to fetch the HomeTabBarController that’s in the storyboard.
I finally found the solution: As #matt suggested I had to fetch the HomeTabBarController that’s in the storyboard.
window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
// controller identifier sets up in storyboard utilities
// panel (on the right), it called Storyboard ID
let viewController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
window?.makeKeyAndVisible()
window?.rootViewController = viewController

iOS Swift - implementation of SplitViewController inside a Container View

I'm following this tutorial link
But with one change that I made since the beginning.
I Added a ViewController (and made it the Initial View Controller) and Added a Container View in it.
Then I embed seagued between my View Container and the tutorial's SplitViewController.
And all worked well, until I got to this step:
Go to to AppDelegate.swift and replace the implementation of application(_:didFinishLaunchingWithOptions:) with the following:
guard let splitViewController = window?.rootViewController as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let detailViewController = splitViewController.viewControllers.last as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
return true
How this code should be modified to work with my case?
In your case you can't get access to uisplitviewcontroller in AppDelegate. Since you are using Container Embedded view like in image below. You get reference of the UISplitviewcontroller from prepareFor segue of your first viewController. So instead of writing code in AppDelegate, try do that in prepare for segue in your initial viewController.
Initial ViewController
class ViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "embedseg" {
guard let splitViewController = segue.destination as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let rightNavController = splitViewController.viewControllers.last as? UINavigationController,
let detailViewController = rightNavController.topViewController as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
masterViewController.delegate = detailViewController
detailViewController.navigationItem.leftItemsSupplementBackButton = true
detailViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}
}
}

How to switch between uiViews from a non UIView class

So here's the situation. I have an app which presents a tabBarController as its root view controller, with a number of tabItems. So here's the setup in my app delegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let vc1 = VC1(nibName: "VC1", bundle: nil)
let vc2 = VC2(nibName: "VC2", bundle: nil)
let menuTabBarController = MenuTabBarController(nibName: "MenuTabBarController", bundle: nil)
menuTabBarController.viewControllers = [VC1,VC2]
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = menuTabBarController
window?.makeKeyAndVisible()
//Setup tab bar
UITabBar.appearance().barTintColor = UIColor.blackColor()
let IMG1 = UIImage(named: "img2.png")
let IMG2 = UIImage(named: "img2.png")
VC1.tabBarItem = UITabBarItem(
title: "View 1",
image: IMG1,
tag: 1)
VC2.tabBarItem = UITabBarItem(
title: "View 2",
image: IMG2,
tag:2)
return true
}
func applicationWillResignActive(application: UIApplication) {
}
func applicationDidEnterBackground(application: UIApplication) {
}
}
So notice I have two UIViewController classes(VC1 and VC2) nested within the menuTabBar. Now from menuTabBar class, I can easily switch between the views like so
class MenuTabBarController: UITabBarController,UITabBarControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self//Set tabbarcontroller delegate
}
// UITabBarControllerDelegate
func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
tabBarController.selectedIndex = 1;//Say I wanted to transition to VC2
}
}
But What I ultimately want to do is to be able to switch between the two UIViewControllers from another class that is not a UIViewController. I attempted something like this
class Actions(){
func someFunctionThatSwitchesToVC2(){
//So I create a reference to appDelegate which in turn, is supposed to reference the tab bar and switch between its child views
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let tabBarController: UITabBarController = (appDelegate.window?.rootViewController as? UITabBarController)!
tabBarController.selectedIndex = 1
}
}
When I run the someFucntionThatSwitchesToVC2, I get this error "fatal error: Index out of range". Obviously I'm not doing something right. Any ideas greatly appreciated
PS, When I do tabBarController.selectedIndex = 0, I don't get the error but nothing happen
I think you are doing typo while assigning ViewControllers. Change this line:
menuTabBarController.viewControllers = [VC1,VC2]
with below line:
menuTabBarController.viewControllers = [vc1,vc2]

Swift 2: How to Load UITabBarController after Showing LoginViewController

Am new to Swift and Storyboard. At initially I have to show the login page and from the login page to UITabBarController. Once the user remembered the login details I have to check the login details in the AppDelegate and show the UITabBarController directly if the user already logged in. I have referred some SOF questions but, am not getting the result.
I designed the LoginViewController embedded with
UINavigationController. And I have one UITabBarController with 2
viewcontrollers. I set the LoginViewController as a
inititialViewController in Storyboard. So the loginview is showing at
very first time. But, I don't know how to push the UITabBarController
from the login screen (Login Button Action). Also I don't know how to
check and load the login and tabbar
respectively from appDelegate.
Can anyone please help me? Thanks in advance.
#IBAction func loginButtonAction (button : UIButton) {
if isRemeberLogin == true {
let loginClass = LoginModelClass(userNameValue: (usernameTF?.text)!, passwordValue: (passwordTF?.text)!)
print("Remembering Login Details: \(loginClass.userName, loginClass.passWord)")
}
let homeVC = self.storyboard?.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
let collectionVC = self.storyboard?.instantiateViewControllerWithIdentifier("ItemsCollectionViewController") as! ItemsCollectionViewController
//self.navigationController?.pushViewController(homeVC, animated: true)
let tabBarController = self.storyboard?.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
print("TABBAR \(tabBarController)")
let viewControllersArray = [homeVC, collectionVC];
// tabBarController?.viewControllers = viewControllersArray
self.navigationController?.pushViewController(tabBarController, animated: true)
}
Thank you for the answers. I resolved the issue and here is my code.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch
let username = NSUserDefaults.standardUserDefaults().objectForKey("Username")
print(username)
let storyBoard: UIStoryboard = UIStoryboard(name:"Main", bundle: NSBundle.mainBundle())
if username?.length > 0 {
print("User already logged In")
let tabBarController: UITabBarController = storyBoard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = tabBarController
} else {
print("New User")
let loginViewController: ViewController = storyBoard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = loginViewController
}
return true
}
This is from Login Button Action:
let storyboard: UIStoryboard = UIStoryboard(name:"Main", bundle: NSBundle.mainBundle())
let tabBarController: UITabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window!.rootViewController = tabBarController
Just mention the "TabBarController" as Identity in Storyboard for the UITabBarController. I have created a Viewcontroller embedded with UINavigationController and UITabBarController with three UIViewControllers separately.
I hope it will help someone else. Thanks.
Please check in image your storyboard must be look like following.
Then give Storyboard Segue identifier which navigate you to UITabbarController from LoginViewController.
Then paste following code from where you want to navigate.
#IBAction func btnLogin_Click(sender: AnyObject) {
self.performSegueWithIdentifier("LoginToTabBar", sender: self)
//LoginToTabBar is identifier which you settled out in storyboard segue.
}

Resources