push UISplitViewController upon login using swift - swift

I am trying to push UISplitViewController upon button click but not having much luck. When I run the app I have the FirstViewController which is on the storyboard as the intial screen which only have a button, upon button click I want to push UISplitViewController, below is the code I am using upon button click, can someone please suggest what I am doing wrong, thnx
#IBAction func launchSplitView(sender: AnyObject)
{
let leftVC = LeftViewController()
let detailVC = RightViewDetailController()
let splitViewController = UISplitViewController()
//splitViewController.delegate = //UIApplication.sharedApplication().delegate as AppDelegate
splitViewController.viewControllers = [leftVC,detailVC];
//splitViewController.delegate = self
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
window?.rootViewController = splitViewController
// window.makeKeyAndVisible()
}

You can't use window?.rootViewController because your storyboard is the rootViewController instead you should use presentViewController
#IBAction func launchSplitView(sender: AnyObject){
let leftVC = LeftViewController()
let detailVC = RightViewDetailController()
let splitViewController = UISplitViewController()
splitViewController.viewControllers = [leftVC,detailVC];
self.presentViewController(splitViewController, animated: true, completion: nil)
}

For now this is the solution I found
=>I was able to launch through segue but not programmatically
When I programmatically launch using "launchSplitView function", I have issues with TableviewController which is the first view controller in split view but when I use segue it works. Not sure if its a bug or what. Segue is good enough for now.

Related

Xcode 11 Segues

Whenever I am using segues in the Xcode 11 beta (here just changing between two VCs using a swipe gesture), the second VC pops up as a card:
How can I prevent this?
Id take a look at this article. It explains well why its happening and gives an example of how to revert it back to the standard style.
View Controller Presentation Changes
If anyone is doing the segue programmatically, the code needs to be something similar to this:
#objc func buttonClicked(_ sender: UIButton) {
let vc = ViewControllerB() //Destination controller
vc.modalPresentationStyle = .fullScreen // This line is needed now
vc.modalTransitionStyle = .flipHorizontal
self.present( vc, animated: true, completion: nil )
}

Swift 3+: Multiple Storyboards with TabBarController. Set TabBarController Tab, Segue to desired ViewController

Working in multiple storyboards. Getting from point A->TabBarController(tab 2)->NavigationControllerA->StoryboardReference->NavigationControllerB->ViewControllerA->ViewControllerB. No need for data passing.
My tab bar controller is set up in its own storyboard, with each tab going through a navigation controller to a storyboard reference. Then the storyboard reference links to another storyboard (obv.), and through a navigation controller to ViewControllerA. I then want to go to performSegue to ViewControllerB. This is all done from a UIViewController Extension.
From what I've been reading, I should approach like this:
let tab = 2
let sbOne = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = sbOne.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController
tabBarController.selectedIndex = tab
let sbTwo = UIStoryboard(name: "sbTwo", bundle: nil)
let viewControllerA = sbTwo.instantiateViewController(withIdentifier: "ViewControllerA")
performSegue(withIdentifier: "toViewControllerB", sender: self)
I receive NSInvalidArgument: Point A "has no segue with identifier 'toViewControllerB'"
Swift 3+
I’d be surprised if this is the best answer but this is the only solution that worked. A bit of my problem stemmed from lack of understanding. But the concept I arrived at was to separate the functions into two parts. Setting the tabbarcontroller tab, then segueing to the destination using a variable struct.
I ended up setting a struct at Point A.
struct Destination {
static var currentID = Int()
}
And on button press I would set the variable with this and then and call the function below:
Destination.currentID = currentID
goToViewControllerA()
Then using part of the code I had before I could set the tabbar Controller as the root view controller and go to ViewControllerA (the first view controller) on the selected tab. This is done in an uiviewcontroller extension but can also be done in a function in Point A.
goToViewControllerA(){
let tab = 2
let sbOne = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = sbOne.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController
tabBarController.selectedIndex = tab
}
It’s then just a matter of checking if the struct static var is set, and segueing to the destination controller (ViewControllerB). This is done in ViewControllerA, or if you have to segue through multiple view controllers you could model your function on each viewcontroller using this in the viewdidload.
If Destination.currentID != Int() {
performSegue(withIdentifier:“toViewControllerBSegue”, sender:self)
}
I’d love to learn a better way of doing this if it exists.

Attempt to present * whose view is not in the window hierarchy

I am using the following code in AppDelegate to display a popup window within the app when a button is selected, i will eventually move this to a label hyperlink but just testing currently.
let storyboard = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("test") as! ViewController
let popOverVC = UIStoryboard(name:"Main", bundle: nil).instantiateViewControllerWithIdentifier("sbPopUpID") as! PopUpViewController
storyboard.addChildViewController(popOverVC)
popOverVC.view.frame = storyboard.view.frame
storyboard.view.addSubview(popOverVC.view)
popOverVC.didMoveToParentViewController(storyboard)
self.window?.rootViewController?.presentViewController(storyboard, animated: true, completion: nil)
The first time i select a button this works correctly, however on all subsequent button presses the following error is displayed.
2016-10-28 11:27:40.551 testfordeeplinks[20496:104536] Warning:
Attempt to present
on whose view is not
in the window hierarchy!
For anyone who stumbles across this in the future, this is how i resolved;
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = storyboard
rootViewController doesn't necessarily refer to the view controller that is currently visible. For example, if you utilise a UINavigationController, rootViewController will hold a reference to that navigation controller which in itself is buried deep in the view hierarchy and hence when you try to present a view controller on it get an error. What I would recommend doing is grabbing the last view controller in navController.viewControllers and presenting your popup on that. See the following code:
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
if let navController = appDel.keyWindow?.rootViewController as? UINavigationController {
if let visibleVC = navController.viewControllers.last {
visibleVC.presentViewController(storyboard, animated: true, completion: nil)
}
}
Give that a try and let me know. :)

Swift 2 - Open Split View Controller

I have a UISplitViewController in my iOS app, but my initial view controller is a normal UIViewController.
I want to open the UISplitViewController when a button is clicked on the UIViewController:
#IBAction func openSplitViewController(sender: AnyObject) {
let splitViewController = UISplitViewController()
let leftNavController = splitViewController.viewControllers.first as! UINavigationController
let masterViewController = leftNavController.topViewController as! MenuTableViewController
let rightNavController = splitViewController.viewControllers.last as! UINavigationController
let detailViewController = rightNavController.topViewController as! DetailViewController
splitViewController.viewControllers = [masterViewController,detailViewController];
self.presentViewController(splitViewController, animated: true, completion: nil)
}
But when I click the button, I get:
fatal error: unexpectedly found nil while unwrapping an Optional value
How should I be opening the UISplitViewController from the UIViewController?
Your error has nothing to do with a UISplitViewController, the error you get is because one or more of your arguments is nil.
So make sure that all of the viewControllers you create are real and not nil.
Look for instance at this line:
let leftNavController = splitViewController.viewControllers.first as! UINavigationController
At this point your splitViewController has no viewControllers assigned, so leftNavController will be nil. You will need to create the navController and viewController before adding them to your splitViewController.

iOS change tab programmatically

I'm developing an iOS application with a tab bar and navigation. When I press a button in the first tab I want it to load the second tab with a navigation controller and push the next view. Can someone help with this?
You can programatically select tab by
self.tabBarController.selectedIndex=1;
The button in the first tab sends a message to the tab controller, telling it to select the second tab. Then you send a message to the rootView of the second tab, which is a navigation controller, and tell it to push such and such an object that you create in the class with the first button.
Set selectedViewController:
self.tabBarController.selectedViewController = viewControllerYouWant;
For example,
self.tabBarController.selectedViewController
= [self.tabBarController.viewControllers objectAtIndex:2];
Here is a Swift solution for anyone that needs it. I had to do the same thing just go from a nested view controller in tab 2 to another nested view controller in tab 4. Here is how I achieved that:
func goToHelpViewController(){
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let desiredIndex:Int = 3
self.tabBarController?.selectedIndex = desiredIndex
let settingsStoryBoard = UIStoryboard(name: "SettingsSection", bundle: nil)
let helpViewController = settingsStoryBoard.instantiateViewControllerWithIdentifier("HelpViewController") as! HelpViewController
let settingsRootNavigationController = self.tabBarController?.viewControllers![desiredIndex] as! UINavigationController
settingsRootNavigationController.popToRootViewControllerAnimated(false)
settingsRootNavigationController.pushViewController(helpViewController, animated: true)
})
}
Swift 3.0
func goToHelpViewController(){
DispatchQueue.main.async(execute: { () -> Void in
let desiredIndex:Int = 1
self.tabBarController?.selectedIndex = desiredIndex
let settingsStoryBoard = UIStoryboard(name: "SettingsSection", bundle: nil)
let helpViewController = settingsStoryBoard.instantiateViewController(withIdentifier: "HelpViewController") as! HelpViewController
let settingsRootNavigationController = self.tabBarController?.viewControllers![desiredIndex] as! UINavigationController
settingsRootNavigationController.popToRootViewController(animated: false)
settingsRootNavigationController.pushViewController(helpViewController, animated: true)
})
}