Here is the layout of my app
I am trying to access a variable of startViewController from within TableViewController.
When I print the viewControllers of splitViewController (print(self.splitViewController?.viewControllers)) from within tableViewController this is what I get
Optional([<UINavigationController: 0x12200f600>, <temp.CollectionViewController: 0x121e16860>])
That second viewController(temp.CollectionViewController) should be of type startViewController.
The startViewController in my program presents the collectionViewController using a segue with kind show. The collectionViewController has already been segued to when I call print(self.splitViewController?.viewControllers).
try to cast it as below :
splitViewController?.viewControllers.forEach({ (vc) in
if let startController = vc as? startViewController {
--- Your code ---
return
}
})
I ended up needing to put StartViewController inside a UINavigationController. I was then able to access the first viewController with
var detailStart = (splitViewController?.viewControllers[1] as? UINavigationController)?.viewControllers.first as? StartViewController
I then hid the unwanted navigation bar with
navigationController?.setNavigationBarHidden(true, animated: false)
Which was placed inside viewDidAppear
This ended up being an ok solution for me, because I needed to put CollectionViewController inside a UINavigationController anyway, but it seems kind of hacky and maybe not the best practice
Related
I have a LoginView, where after user authentication the user is sent to a corresponding homeView. The transition is made programmatically without segue. Then, depending on the user type (lets say, superuser and tester), the user can browse from his homeView. Both homeViews are preceded by a NavigationController.
NavigationController -Segue-> SuperView -Segue-> SecondView
->LoginView |
NavigationController -Segue-> HomeView <-Segue -
|
-Segue-> View4 -Segue-> View5 ...
Here is the storyboard flow
And the problem: in the simulator, after the login, the first view looks great, but all the next views don't have a navigation bar. In the storyboard, however, everything looks fine.
The transition is made as follows:
func transitionToSuperHome() {
let supervisorViewController = storyboard?.instantiateViewController(identifier: "superVC") as? SuperuserViewController
view.window?.rootViewController = superuserViewController
view.window?.makeKeyAndVisible()
}
and
func transitionToHome() {
let homeViewController = storyboard?.instantiateViewController(identifier: "homeVC") as? HomeViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
This is how the second (and all subsequent) view looks like
any idea what can cause the problem?
It looks to me like you are setting the root view controller in a detached state. A simple fix might be to embed your root view controller inside of a navigation controller in order to avoid the detached state. This is also why your screenshots appear to be presented modally instead of in a navigation stack.
window?.rootViewController = UINavigationController(rootViewController: homeViewController)
I have inherited a storyboard that launched directly to a UITabBarController. In the AppDelegate.swift file in the didFinishLaunchingWithOptions method there is the following code:
//let loginScreen = window!.rootViewController
let tabController = window!.rootViewController as! UITabBarController
let navController = tabController.viewControllers![0] as! UINavigationController
let salaryController = navController.topViewController as! SalaryTableViewController
let nav2Controller = tabController.viewControllers![1] as! UINavigationController
let employeeController = nav2Controller.topViewController as! EmployeeTableViewController
I am trying to change the code so the login screen is the rootViewController but when I remove the rootViewController from the tabController assignment I get an error that casting a UITableViewController to UITabBarController always fails. Does anyone know why casting a UITableViewController to a UITabBarController always fails unless the UITableViewController is the rootViewController? Is there a way to change the launch screen to a different controller without changing the rootViewController assignment? Here is the storyboard for visual:
enter image description here
UITabBarController is a subclass of UIViewController. You cannot cast superclass to subclass. (Viceversa is possible)
To implement your idea, you should remove initialing your root view controller from storyboard and do it programmatically. Because now, the Xcode think your initial view controller is UITabBarController and the only way is that you instantiate your class programmatically and then make it root view controller.
Why don't you present your login VC as a modal view controller? That way you didn't need to change anything on the view hierarchy.
How to dismiss any View Controller without using Storyboard ? and do I have to use UINavigationController to achieve this ? if not how then ?
if someone is still struggling to dissmiss on swipe (left,right,bottom,top)
i came across a very elegant and decent cocapod panslip
with a very simple usage
just call this method in viewDidLoad()
For viewController embedded in navigation Controller
let viewControllerVC = self.navigationController
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissming
}
For Simple View Controller
let viewControllerVC = self
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissming
}
For TableView embedded in View Controller
let viewControllerVC = self.YourTableview.parentContainerViewController()
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissminn
}
The way to dismiss a view controller is to call a dismiss method on the presenting view controller. If you presented your child controller from a parent by calling self.present(_:animated:) then you can call self.dismiss(animated:). If you used a navigationController and called navigationController.push(_:animated:) then you need to tell the navigation controller to dismiss with navigationController.popViewController(animated:)
Method names might not be exact, but you should be able to figure it our with autocomplete.
If you want to swipe right is not a dismiss, but I think that what you want it to embed the UIViewController inside a UINavigationController.
For example:
if let vc = UIStoryboard(name: "YourStoryboard", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController {
let navigation = UINavigationController(rootViewController: vc)
navigationController?.pushViewController(vc, animated: true)
}
I can swap from one UIViewController to another within a UITabBarController using tabBarController?.selectedIndex = targetIndex. I would like to know how to trigger a segue after the switch.
I have tried doing if let vc = tabBarController?.viewControllers?[0] as MyViewController {} and calling vc.performSegue() but it errors out, complaining that it's a UINavigationController. (I couldn't even get vc.prepare() to work but I can't work out how to create a UIStoryBoardSegue, which it requires as the first argument, from scratch using the segue identifier.) I think this is because all of my UIViewControllers in the UITabBarController are within Navigation Controllers.
How do I switch from index 0 to 1 in the tab bar controller, and then trigger a segue in the view controller embedded in the navigation controller? Note, I need to pass in a copy of the calling object (my UIViewController) or a payload for contextual purposes to the UIViewController being segued to.
Well like you said the viewController which is presented at the index is a UINavigationController. You should get the rootViewController of the UINavigationController and perform the Segue on the RootViewController.
Below code should work:
self.tabBarController?.selectedIndex = 1
guard let vc = self.tabBarController?.viewControllers?[1] as? UINavigationController else {
return
}
guard let rootVC = vc.viewControllers.first as? SecondViewController else {
return
}
rootVC.vc = self
rootVC.performSegue(withIdentifier: "test", sender: self)
I need to assign data source to a view controller segued by press a button in appdelegate.swift. How can I find the view controller by a segue identifier. I know I can find in a navigation controller by
let navigationController = window!.rootViewController as! UINavigationController
let controller = navigationController.viewControllers[0] as! ListViewController
like this. Is there a way to find a view controller when only the segue is connected with the previous view controller?
In other words, how to identify any vc in a project? Is storyboard ID used for this?
let viewController = segue.destinationViewController as! ListViewController