presenting and pushing viewcontrollers in swift 3.0 - ios

I am working in storyboard and also programmatically do some things. First, I have created a viewController controller which is login page (first view) programmatically. But in storyboard I have a NavigationController whose root is ViewController. Everything (methods forgotPassword and loginDidFinish) worked fine, except that ViewController was viewed before controller immediately after launching the app.
So I have changed the root of NavigationController to controller, and after that my functions does not work. I've tried several things like deleting navcontrol in storyboard, etc. You can see my project here: https://github.com/ardulat/SPE

I will provide you a basic example of a Login scenario, hope it can help you with your issue, what I would do first is set right the navigation between ViewControllers like this:
I have two view controllers in my project (LoginViewController.swift and MainViewController.swift):
So in my storyboard I create two ViewControllers, the first one embedded with NavigationController then I set a segue from my first ViewController to my second ViewController:
Then I give a name to the segue I created like so:
And in order to navigate from Login to Main ViewController, I call the performSegue method inside the loginButtonTapped action that is triggered when the login button is touched.
LoginViewController.swift:
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginButtonTapped(_ sender: AnyObject) {
// TODO: validate your login form
performSegue(withIdentifier: "LoginToMain", sender: nil)
}
}

Related

performSegueWithIdentifier doesn't work in a different ViewController

I have the following storyboard: Main Storyboard
In it, several custom View Controllers are programmatically embedded in the Scroll View. In one of them, a button is present and should trigger a segue to show the "hey" screen.
I have then wrote the following code:
#IBAction func addNewDateButtonDidTouched(sender :AnyObject) {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let storyboardInit = mainStoryboard.instantiateViewControllerWithIdentifier("mainview")
storyboardInit.performSegueWithIdentifier("showNewDate", sender: self)
}
This #IBAction seems to reload the inital view controller and perform the segue correclty (Xcode doesn't return any error). But the "hey" screen doesn't show up and its viewDidLoad() doesn't load.
Any hint?
Instead of calling
storyboardInit.performSegueWithIdentifier("showNewDate", sender: self)
try
self.performSegueWithIdentifier("showNewDate", sender: self)
The storyboardInit in your code will instantiate a UIViewController that has an identifier "mainview".
But this UIViewController hasn't been added to the screen, when you're asking the controller to perform a segue.
So, I wouldn't do that. What I would do, to segue to the hey screen is either :
Create a segue from the current controller and just do this in the code : self.performSegueWithIdentifier
Instantiate the hey controller like this : instantiateViewControllerWithIdentifier, and then just do the self.presentViewController
So, to transition to a new controller, you have to start from the current controller.
if i understand your viewcontroller hierarchy correctly...
since the viewcontroller that contains the button to trigger the segue is a childviewcontroller of the viewcontroller that has the segue setup in storyboard i think you have to call presentingViewController?.performSegueWithIdentifier("showNewDate", sender: self).

How can I use my action and programmatically transition to a view controller as defined in the storyboard?

I have a sent Action, as follows:
#IBAction func showSettings(sender: AnyObject) {
let settingsPicker = SettingsViewController()
settingsPicker.setDelegate(self)
let navigationController = UINavigationController (rootViewController: settingsPicker)
self.presentViewController(navigationController, animated: true, completion: nil)
}
The method creates a controller, sets a reference to the delegate, and creates a navigation controller.
All this works, however the widgets defined in the story board do not appear. The SettingsViewController should manage a ui which is defined in a story board. I presume becuase I create it programmatically none of the widgets appear. The SettingsViewController does not programmatically create widgets, the are declaratively defined in the story board.
If I link (in the storyboard) the two controllers with a segue, then the widgets appear, but my action is not being used.
How can I use my action and present the view controller / ui as defined in the storyboard?
When you create a segue between your UIViewControllers, you should define an identifier, eg: "settingsSegue".
In your code you can then perform that segue by calling the segue with the identifier:
#IBAction func showSetting(sender: AnyObject) {
performSegueWithIdentifier("settingsSegue", sender: nil)
}
To set up the SettingsViewController you should implement the following:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if let settingsController = segue.destinationViewController as? SettingsViewController {
settingsController.delegate = self
}
}
Interacting with Storyboard and Segues
If you want to invoke a segue through code, see Laffen's answer.
If you want to create a view controller that's defined in your storyboard and then display it programmatically, use instantiateViewControllerWithIdentifier to create a new instance of your view controller, then display it to the screen as desired (present it modally, push it onto your navigation stack, or whatever you want to do.)

UIPageViewControllerDataSource - segueForUnwindingToViewController not being called

I have a UIViewController that is set up as a UIPageViewControllerDataSource named MainPVC.swift. It is my entry point on my Storyboard. In it, I am instantiating another UIViewController named TrackerVC which is set up in my Storyboard - but not connected to MainPVC by segue.
Instantiating TrackerVC:
func viewControllerAtIndex(index: Int) -> TrackerVC {
let childViewController = self.storyboard?.instantiateViewControllerWithIdentifier("trackerVC") as TrackerVC
childViewController.screenIndex = index
return childViewController
}
I have another UIViewController named NotesVC. When I push a button on TrackerVC, I use a custom UIStoryBoardSegue to display NotesVC. On NotesVC, I have another button that I want to return to TrackerVC using another custom UIStoryboardSegue via Unwind.
Cancel button tapped in NotesVC:
#IBAction func cancelButtonTapped(sender: AnyObject) {
self.performSegueWithIdentifier("unwindFromNotesSegue", sender: self)
}
Now to my issue -
When I push the button on TrackerVC, the custom UIStoryboardSegue works great and displays NotesVC as expected. However, when I tap the button on NotesVC, the custom UIStoryboardSegue is ignored and the generic segue that slides the view down is being used.
I have traced the issue down to segueForUnwindingToViewController not being called in TrackerVC. I have all of my connections set up properly in my Storyboard and all of the required methods (the method unwind uses).
I have also tried creating a 3rd UIViewController and displaying it using the custom UIStoryboardSegues along with Unwind and calling it from NotesVC and everything works fine. segueForUnwindingToViewController is being called on NotesVC as expected.
Thanks for any help!
Do you have NavigationController attached? You may need to subclass the NavigationController and add the segueForUnwindingToViewController there. It's what solved the similar problem I was having.

Unwind segue doesn't work SWIFT

I have a navigation controller, with a table view. When I press a cell, the detail view controller opens.
In my root view controller I have :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailview" {
var destination:DetailViewController = segue.destinationViewController as DetailViewController
destination.delegate=self
}
}
In my detail view controller I have a back button :
#IBAction func back() {
self.navigationController?.popViewControllerAnimated(true)
}
The issue is, after 2 go to and return, my app crashes when I go back on the root view controller pressing back button. The console doesn't give me errors. It just crashes.
I think I have forgotten to unwind the segue.
So in my detail view controller I added :
#IBAction func unwindToViewController(segue: UIStoryboardSegue) {
println("unwind function")
}
I connect this function to my back button with "exit" in my storyboard.
When I run my app, If I press on the back button, the console doesn't display my print "unwind function", so unwindToViewController isn't called. Why ?
And my app still crashes...
Your unwindToViewController method should be placed in your root viewController, then ctrl-drag from the button in the detailViewController to the Exit icon in InterfaceBuilder. Choose that method in the popup menu.
Another approach would be to declare a protocol with a function in the rootViewController that is called from the detailViewController. You already set the rootViewController as the delegate of the detailViewController. Within that function you call dismissViewController.
Swift answer...
I had a similar problem.
The func: "segueForUnwindingToViewController(toViewController: UIViewController, fromViewController: UIViewController, identifier: String?) -> UIStoryboardSegue" was never called.
Solution:
since I didn't have a "UINavigationController", because I simply embeded the app in a Navigation Controller, I created a UINavigationController subclass for the Navigation Controller and added the function named above on it. Now the app calls "segueForUnwindingToViewController"

Calling segue programmatically not working

I am trying to make a splash screen. I have a view that has a background image being drawn onto it and then another view I want to transition to after a few seconds. I am trying to use the following code:
self.performSegueWithIdentifier("showApp", sender: self)
I created a segue between the two views by ctrl+dragging a line from one to the other. I set the segue's identifier to "showApp".
When I run the code nothing happens and there are no errors. Any ideas?
Here is the controller for the splash screen:
class SplashViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
sleep(2)
// THIS DOES NOTHING:
self.performSegueWithIdentifier("showApp", sender: self)
// THIS AS SUGGESTED ALSO DOES NOTHING:
var otherViewController:UIViewController = self.storyboard.instantiateViewControllerWithIdentifier("test") as UIViewController
self.presentViewController(otherViewController, animated: true, completion: nil)
}
}
Normally, you need a navigation controller in order to use segue.
Highlight your SplashViewController object inside the Storyboard and go to
Editor -> Embeded In -> Navigation Controller
After that, remove the code suggested by Clement and try running the project again, you should get the result that you expected.

Resources