How to present a view controller inside a navigation controller SWIFT - swift

I have VC1 which is a basic view controller, I then want to present VC2 which is inside a navigation controller. Whenever I present it, it doesn't display the navigation controller. I want this all done pragmatically. The code I have been using to present VC2 is:
func matchesPressed(sender: UIButton!) {
let matchesTVC: Matches = self.storyboard?.instantiateViewControllerWithIdentifier("Matches") as! Matches
self.presentViewController(matchesTVC, animated: true, completion: nil)
}
How do I present the navigation controller it is inside as well?

Is the navigation controller in the storyboard? If so, give it a storyboard ID and replace your matchesTVC stuff with the navigation controller.
If matches is a standalone view controller in the storyboard, you can do it in code like this:
let matchesTVC: Matches = self.storyboard?.instantiateViewControllerWithIdentifier("Matches") as! Matches
let navContr = UINavigationController(rootViewController:matchesTVC)
self.presentViewController(navContr, animated: true, completion: nil)

Instantiate the navigation controller that contains your view controller and present the navigation controller.

Related

Swift How can I add Navigation Controller after creating Views

I created View Controllers and I want to add Navigation Controller now. I tried embed-in Navigation Controller to My DetailViewContoller(colorful View Controller) but I got an error. main.storyboard, error. How can I add Navigation Controller ?
In order to set view controller as navigation controller, you can set it programmatically by calling this function in appdelegate or scenedelegate or any point.
func setNavigationController() {
var viewController: UIViewController
let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "myVCID")
let rootViewController = UINavigationController(rootViewController: viewController)
rootViewController.setNavigationBarHidden(true, animated: false)
self.view.window?.rootViewController = rootViewController
}
If you want to set navigation controller through storyboard, then you have to first add navigation controller and set is root view controller to the controller you want to make it navigation controller.

How to do popViewController from another class?

My app has a TabBarController. Each tabBarItem relates to a ViewController embedded in a NavigationController.
When in first tabBarItem and selecting another tabBarItem I want to do some stuff before moving to the selected ViewController. Therefore I created a class for my tabBarController and made it UITabBarControllerDelegate.
What I want to do is present an alert with two buttons; button A cancels the move to the selected viewController and button B lets the move happen.
My problem is that when button B is pressed, I want to popToRootViewController. I gave the navigationController a storyboardID and tried to instantiate it like shown below.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let alert = self.storyboard?.instantiateViewController(withIdentifier: "ActiveSessionWarningAlert") as? ActiveSessionWarningAlert {
alert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
alert.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
let alertWasDismissed: (Bool) -> Void = { userWantsToMoveToSelectedViewController in
if userWantsToMoveToSelectedViewController {
if let navContr = self.storyboard?.instantiateViewController(withIdentifier: "firstNavContr") as? UINavigationController {
navContr.popToRootViewController(animated: true)
}
tabBarController.selectedViewController = viewController
}
}
alert.alertWasDismissed = alertWasDismissed
self.present(alert, animated: true, completion: nil)
}
return false
}
Everything works as expected, but the popToRootViewController doesn't seem to occur; when selecting the first tabBarItem again the same viewController that was 'active' when we left the item is still showing.
I checked so that the viewController I want to pop is actually in the navigation stack and that the navContr != nil.
What am I missing?
You don't say so, but I'm assuming that the alertWasDismissed closure you pass to your alert view controller gets invoked when the user dismisses the alert.
The problem with your closure is this bit:
if let navContr = self.storyboard?.instantiateViewController(withIdentifier: "firstNavContr") as? UINavigationController
Any time you call instantiateViewController(withIdentifier:), you are creating a brand new, never before seen instance of a view controller (a navigation controller in this case.) That navigation controller has nothing to do with the one that belongs to the current tab that you are trying to dismiss. It doesn't have anything in it's navigation stack other than the root view controller that is defined in the storyboard.
What you need to do is find the navigation controller of the current tab in your tab bar controller's tabBarController(_:shouldSelect:) method, and pass that navigation controller to your alertWasDismissed closure.
At the time the tabBarController(_:shouldSelect:) method is called, the tab bar controller's selectedViewController should contain the current view controller. Replace the line above with:
if let navContr = tabBarController.selectedViewController? as? UINavigationController {}
That should work.

Deinitialize presented view controller

I have the next function
func switchRootViewController(rootViewController: UIViewController) {
let window = UIApplication.shared.windows.first!
window.rootViewController = rootViewController
window.makeKeyAndVisible()
}
And I use it in a presented view controller, ex in PresentedViewController.
let navigationViewController = UINavigationController(rootViewController: PresentedViewController())
present(navigationViewController, animated: true, completion: nil)
But when I switch to the needed view controller, my presented view controller doesn't deinitialize. I have to use this way, first dismiss:
self.dismiss(animated: true, completion: {
switchRootViewController(rootViewController: HomeViewController.instantiate())
})
instead of simple
switchRootViewController(rootViewController: HomeViewController.instantiate())
UIViewController objects are retained when presented by another UIViewController. To release your view controllers, they need to be removed from the view hierarchy, which you can accomplish by dismissing them. As far as where to dismiss your view controller, I'm not sure because you haven't given enough information. But you need to dismiss any view controller that you want released from memory.

AVPlayerViewController not rotating

My custom AVPlayerViewController won't autorotate if the previous view controller has been instantiated. If I present the AVPlayerViewController, it rotates, and if I present the previous view controller, it rotates. Here's my code for instantiating a view controller :
let vc = self.storyboard!.instantiateViewController(withIdentifier: "MovieVC") as! MovieVC
vc.movie = self.movie
self.navigationController?.pushViewController(vc, animated: true)
In this situation I am creating a copy of the current view controller with different information. If there is no way to fix the autorotating error, is there a different way to present the same view controller?
The problem is that you are not presenting the view controller. You are pushing it. That means that the navigation controller itself is in charge of rotation, so you don't get any special autorotation for this view controller.
The only way to give this view controller its own power over autorotation is to present it:
self.present(vc, animated: true)

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