How to pass two textfield entries to another ViewController with using segue - swift

I want my user to go to the TableViewController once they enter their "id" and "password" but when we use prepare and performsegue methods we just send one variable.
#IBAction func logIn(_ sender: Any) {
performSegue(withIdentifier: "emailSegue", sender: emailTextField.text)
performSegue(withIdentifier: "passwordSegue", sender: passwordTextField.text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let guest = segue.destination as! ExpenseTableViewController
guest.incoming.append(sender as! String)
}
As you can see here I want to perform two different segues and I have also created two segues on the storyboard from ViewController to tableview controller named as "emailSegue" and "passwordSegue", but in the prepare function I can only prepare for the one of them which is the "emailSegue" when I run the code, it does compile and I can append email to the array but not my password.
So I wonder how I can get them both to be sent? Is there a way to prepare for 2 different segues? Could not find an example of it on anywhere else.
Thanks in advance.

You can only perform one segue, but you can send multiple parameters.
Just pass an array rather than a single string:
#IBAction func logIn(_ sender: Any) {
performSegue(withIdentifier: "emailSegue",
sender: [emailTextField.text!, passwordTextField.text!])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "emailSegue" {
let guest = segue.destination as! ExpenseTableViewController
guest.incoming.append(contentsOf: sender as! [String])
}
}
PS: Rather than forced unwrapping the text properties you should validate them:
#IBAction func logIn(_ sender: Any) {
guard let email = emailTextField.text, !email.isEmpty,
let password = passwordTextField.text, !password.isEmpty else {
// show an alert
return
}
performSegue(withIdentifier: "emailSegue", sender: [email, password])
}

You can only perform one segue at a time, so call performSegue only once when you want the transition to happen and set the two variables in prepareForSegue for the destination view controller. It's best to check what type of segue should be prepared by checking segue.identifier property.

Related

How to use tableView.row with NSStoryboardSegue

I'm trying to send details from selected cell in a NSTableView to another ViewController.
I have a button:
#IBAction func detailButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "toDetailsVC", sender: self)
}
And a prepare for segue:
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
let row = self.tableView.row(for: sender as! NSButton)
if segue.identifier == "toDetailsVC" {
let destination = segue.destinationController as! DetailsVeiwController
destination.name = orders[row].name!
}
}
The error:
Could not cast value of type 'Test.ViewController' (0x100022b98) to 'NSButton' (0x7fff8b59b260).
When I check let row = self.tableView.row(for: sender as! NSButton) inside the button, it works fine.
Am I way off here? Where is this going wrong?
self is the view controller. You have to pass the sender which is the button. And I recommend to declare the sender parameter as the concrete type
#IBAction func detailButtonTapped(_ sender: NSButton) {
performSegue(withIdentifier: "toDetailsVC", sender: sender)
}

Moving from one NSViewController to another NSViewController

I am totally new to the Mac apps development. I am facing an issue since last two days but could not succeed.
My problem is the same as question Swiching between 2 diferent NSViewControllers with data.
Could you please help me to understand the process and syntax of how to move from one NSViewController to another.
I have a View controller for login where I have two fields i.e. UserId and password.
On the click of the login button a web API is called to authenticate the user and upon receiving "SUCCESS" as the response, control should be transferred from LoginViewController to ProfileViewController.
I have tried to resole this issue as per the answer of the question (link given) but I am getting an error that. "fromviewcontroller.view.superview cannot be nil."
Create a segue from LoginViewController to ProfileViewController and give an identifier to it like "showProfile".
#IBAction func loginButton(_ sender: Any) {
// Code for validating User.
if response == "SUCCESS" {
performSegue(withIdentifier: "showProfile", sender: sender)
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "showProfile" {
let profileController = segue.destinationController as! ProfileViewController
profileController.data = responseData
}
}
Not using storyboards?
#IBAction func loginButton(_ sender: Any) {
// Code for validating User.
if response == "SUCCESS" {
let profileController = ProfileViewController(nibName: "ProfileViewController", bundle: Bundle.main)
profileController.data = responseData
self.view.window!.contentViewController = profileController
}
}
You have to create a Segue in your Storyboard (Ctrl + Left click the yellow circle button above your LoginViewController and drag it to your ProfileViewController) and then name it something like "showProfile".
When you received your "SUCCESS" you want to call:
//here you enter the name of the segue you want to call
//& in sender the data you want to pass to the new VC.
performSegue(withIdentifier: "showProfile", sender: nil)
this will call
prepare(for segue: UIStoryboardSegue, sender: Any?)
in your current ViewController, so if you want to pass data to your new ViewController, you need to override it.
Example for passing data between ViewControllers :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//asking which segue is called
if segue.identifier == "showProfile" {
//when you called "showProfile", you can be sure that your
//destination is a ProfileViewController
let vc = segue.destination as! ProfileViewController
//passing the data to your new VC
vc.data = sender
}
}

Two "performSegue" in same class to different Viewcontrollers

I am trying to go to two different VC with two different buttons. With the 'newGeneratedListBtn i only want to go to vc1. With the 'newEmptyList' button i want to go to vc3 with a bool value which works. But when i click first button 'newGeneratedListBtn' to go to vc1 I get error: "Could not cast value of type 'AppName.vc1' to 'AppName.vc3'.
Seems like when i click button to vc1 it tries to send the same values as i want to send to vc3. How can i solve this?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
let value = true
//Button to VC1
#IBAction func newGeneratedListBtn(_ sender: UIButton) {
performSegue(withIdentifier: "unwindSegueToVC1", sender: self)
}
//Value to send to VC2
override func prepare (for segue: UIStoryboardSegue, sender: Any!) {
let vc = segue.destination as! ListView
vc.newEmptyListValue = value
}
//Button to VC2
#IBAction func newEmptyList(_ sender: UIButton) {
performSegue(withIdentifier: "valueSender2", sender: self)
}
}
You need to cast for a specific identifier
override func prepare (for segue: UIStoryboardSegue, sender: Any!) {
super.prepare(for:segue,sender:sender)
if segue.identifier == "valueSender2" {
let vc = segue.destination as! ListView
vc.newEmptyListValue = value
}
else {
// it's unwindSegueToVC1
}
}
as both
performSegue(withIdentifier: "unwindSegueToVC1", sender: self)
performSegue(withIdentifier: "valueSender2", sender: self)
with call prepare
The problem is there is only one implementation of prepare(for:sender:), like this:
override func prepare (for segue: UIStoryboardSegue, sender: Any!) {
let vc = segue.destination as! ListView
vc.newEmptyListValue = value
}
Both of your segues pass through that one method. You must use a switch or other condition to figure out which segue this is, and send the info appropriate to that segue.

how to pass data to multiple viewcontrollers from the same button

Here's another version of one of the most popular questions on stackoverflow. Sorry. Thank you.
I have a viewcontroller that has 30 buttons. Each of these buttons can segue to one of 20 viewcontrollers based on a variable that is sent from a previous viewcontroller.
I know how to send data from one viewcontroller to another, and I know how to have a button connect to multiple viewcontrollers dependent on a passed variable, but I don't know how to pass a variable from a button to whatever viewcontroller is specified from the variable...
My viewcontroller looks like this:
#IBAction func didTapButton(_ sender: UIButton) {
if passedvariable == "A" {
performSegue(withIdentifier: "ToA", sender: self)
if passedvariable == "B" {
performSegue(withIdentifier: "ToB", sender: self)
}
I tried adding something like this...
#IBAction func didTapButton(_ sender: UIButton) {
if passedvariable == "A" {
performSegue(withIdentifier: "ToA", sender: self)
let send = segue.destination as! AViewController
send.NewVariableToSend = (sender as! UIButton).title(for: .normal)!}
}
But that's not working... I feel like I'm close but can't connect the dots yet. Any help is greatly appreciated, thanks!
How are you accessing the actual segue from the IBAction method of your UIButton?
This approach is wrong. Use PrepareForSegue method to pass your data to next ViewController. Its a predefined method so all you need is to override this method in your ViewController class.
Try this..
Note:
guard let is used to get rid of crash if you tried to pass any nil value to your next ViewController.
#IBAction func didTapButton (_ sender: Any) {
//First get the clickedButton Object if you do not have IBOutlet of that button
guard let clickedButton = sender as? UIButton else {return}
//Pass the clicked button to Segue perform as a sender
self.performSegue(withIdentifier: "yourSegueIdentifier", sender: clickedButton)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueIdentifier" {
//Now get you destination viewcontroller and type cast it into your desired ViewController class
guard let nextVC = segue.destination as? YourViewController else {return}
//Now convert the sender into your clicked button because you have previously set the clickedButton as sender when you try to perform this segue
guard let clickedButton = sender as? UIButton else {return}
//Now Simply assign this to nextVC
nextVC.button = clickedButton
}
}

How to programmatically seque to multiple view controllers from a button

I have a view controller with a lot (36) of buttons, and I want each of these buttons to segue to a particular view controller based on a variable that was set earlier in the program. In other words, any button could potentially go to 15 different view controllers based on a variable that was sent to the viewcontroller containing the buttons...
I think I can make this work if I click and drag each button to every viewcontroller... but it seems silly and messy.
I tried doing something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
send.variablesent = (sender as! UIButton).title(for: .normal)!}
}
But this only works if I click and drag the button in the storyboard to the "AViewController".
Any help is appreciated, thanks!!
For that you can make segue from SourceViewController to DestinationViewController instead of from Button to Controller, After that when you call perfromSegue in your button action then pass button reference as sender in perfromSegue call.
#IBAction func buttonAction(_ sender: UIButton) {
self.performSegue(withIdentifier: "segueIdentifier", sender: sender)
}
Now in prepareForSegue cast sender to UIButton and set title according to it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
if let button = sender as? UIButton {
send.variablesent = button.titleLabel?.text ?? "Default value"
}
}
}