I'm learning how to pass data between controllers when a button is pressed, so I'm following this answer: Pass data through segue, But I can't make it work, I have 3 buttons and I want to know which button was pressed, so my code in HomeView is:
var buttonPressed: String?
#IBAction func newsTapped(_ sender: Any) {
buttonPressed = "news"
self.performSegue(withIdentifier: "showNext", sender: buttonPressed)
}
#IBAction func tipsTapped(_ sender: Any) {
buttonPressed = "tips"
self.performSegue(withIdentifier: "showNext", sender: buttonPressed)
}
#IBAction func otherTapped(_ sender: Any) {
buttonPressed = "other"
self.performSegue(withIdentifier: "showNext", sender: buttonPressed)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let data = buttonPressed
if let destinationViewController = segue.destination as? TableViewController {
destinationViewController.origin = data
}
And the code in destinationView (TableViewController) is:
var origin: String?
override func viewDidLoad() {
if let dataRecived = origin
switch dataRecived {
case "news":
print("News")
case "tips":
print("Tips")
case "other":
print("Other")
}
}
When I click any of the buttons, it takes me to the TableViewController, but doesn't print anything, I added the If let, since it crashed when the statement was: if let dataRecived = origin, now it never gets inside the if let statement. If I show the content of the variable (mouse over variable in xCode) it shows: ""
Any ideas why it isn't working? Not sure if it has something to do, but HomeView is a ViewController, linked to a Navigation controller that has a TableView (which is destinationView. Thanks for your help
It looks like you're getting incorrect behavior because you're running the switch statement in the viewDidLoad function which happens before the data from the previous view controller gets sent.
try adding a didSet method to the origin property to load the page like this:
class tableVC {
var origin: String? {
didSet {
if let dataRecived = origin
switch dataRecived {
case "news":
print("News")
case "tips":
print("Tips")
case "other":
print("Other")
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Or you could run the switch in the the viewWillAppear method
I think the Issue you are having is in:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let data = buttonPressed
if let destinationViewController = segue.destination as? TableViewController {
destinationViewController.origin = data
}
If you have subclassed a UITableViewCotroller, you have to cast the destination View Controller to that class
`destinationViewController as? myCustomTableViewController:
if let destinationViewController = segue.destination as? myCustomTableViewController {
destinationViewController.origin = data
}
Related
The question is similar to "how to pass data from different viewController" but in this case I need another information, I know how to pass the data from one viewController to another but I don't know how to tell to the second viewController a specific state of an object that is in the first view. In my case I have some buttons in the first view that go in.
button.isHidden = true
after the tap, I want to tell to the second viewController which buttons have been tap, maybe I've to create a variable that represents the status of the button, but I don't know how to do, someone can help me?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" {
guard let vc = segue.destination as? FinalClass else { return }
let guest = segue.destination as! FinalClass
if let user = sender as? User {
}
}
}
where User can be something like
struct User {
var button1 = Button1 tapped
var button2 = Button2 tapped
ecc.
}
Let suppose you have two viewControllers - FirstViewController and SecondViewController.
So First,
Let Declare two Arrays in FirstViewController and SecondViewController something like -
var tappedButtonsArray = NSMutableArray() // In 'FirstViewController'
AND
var previousViewTappedButtonsArray = NSMutableArray() // In 'SecondViewController'
And here is my code to add | remove tapped buttons to | from tappedButtonsArray in FirstViewController -
#IBAction func btnTapped(_ sender: UIButton) { // Single action for all buttons
if (tappedButtonsArray.contains(sender)){
tappedButtonsArray.remove(sender) // Remove previous tapped button on unselect
}
else{
tappedButtonsArray.add(sender) // Add tapped button on select
}
}
And Here is your perform segue method:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" {
guard let secondViewController = segue.destination as? SecondViewController else { return }
secondViewController.previousViewTappedButtonsArray = tappedButtonsArray
}
}
I've done with a simple array concept without any model, so that you can understand the follow. I hope it'll help you to start with.
I have a variable called correctAnswers = 0 at the top of my program, I have a function where every time it is called it adds 1 to the correctAnswers value. I tested that the function was actually changing the variable by making it print after every +1 and sure enough it goes 1, 2, 3, 4 and so on. However I have an end screen that shows the results after the program has reached its limit of questions (10 in this case)
EDIT #2: Here is my prepare for segue function
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
correctAnswers = sender as! Int
secondViewController.gso = self
}
}
And here is the code in my end screen:
var gso: GameScreen?
override func viewDidLoad() {
super.viewDidLoad()
gso = GameScreen()
print(gso?.correctAnswers ?? 100)
}
When I print correct Answers it is still 0.
EDIT #3 I also tried this method of passing it through a segue and it is always nil. Does the fact its not working have anything to do with the fact the variable is being changed in a function? thats the only reason I can possibly think of to explain why nothing is working.
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
class EndScreen: UIViewController{
var recievedAnswers: Int!
override func viewDidLoad() {
super.viewDidLoad()
print(recievedAnswers!)
}
}
EDIT #4 Figured it out! I think.
It appears they changed prepareForSegue and it no longer works, yet xcode does not give you an error? Should another post be made about this??
Code that actually works:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EndScreenSegue"{
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
You're creating a new instance of GameScreen in the viewDidLoad method of your EndScreen view controller. You need to pass the GameScreen object from your previous view controller to this one.
In your segue you're setting the correctAnswers property of your EndScreen view controller, but you're printing the value of gso?.correctAnswers. A new gso was just instantiated prior to this print statement and (I'm assuming) has a default value of 0 which is why you're getting 0 printed out.
You either need to pass the GameScreen through the segue (assuming that you're segueing from GameScreen), like so:
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
correctAnswers = sender as! Int
secondViewController.gso = self
}
}
Or you can just pass the correctAnswers through the segue as you're doing but be sure to use that value, not gso?.correctAnswers
class EndScreen: UIViewController{
var correctAnswers: Int?
override func viewDidLoad() {
super.viewDidLoad()
print(correctAnswers ?? 100)
}
}
You are creating a new instance of GameScreen.
Delete this line gso = GameScreen() from viewDidLoad
For some reason it looks like prepareForSegue no longer works, yet xcode does not give an error when you use it. The correct format now is:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EndScreenSegue"{
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
I have three view controllers like below
I wrote the unwind method in viewcontroller1, and try to receive some data from viewcontroller2 and viewcontroller3 when they unwind to viewcontroller1.
#IBAction func unwindToViewController1(segue: UIStoryboardSegue) {
print("1")
main_content = (segue.source as! MainContentViewController).main_content
}
#IBAction func unwindToViewController2(segue: UIStoryboardSegue) {
print("2")
detailed_content = (segue.source as! SupplementContentViewController).supplement
}
And set the exit unwind segue for both controller 2 and 3 already.
But why the unwindToViewController methods never get called correctly? I think they should be called when I click the button automatically created by the system.
I solve this problem by using delegate instead of unwind. Delegate pattenr is a more explicit way to solve this problem.
By creating a protocol called myDelegate
protocol myDelegate {
func updateMaincontent(main_content : String)
func updateSupplement(supplement: String)
}
And create a delegate instance inside the second view controller
var delegate: myDelegate?
Then in the first view controller, make the class extend myDelegate and set this delegate of second view controller to self in the func prepare(for segue: UIStoryboardSegue, sender: Any?) method
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationViewController = segue.destination as? MainContentViewController {
destinationViewController.main_content = self.main_content
destinationViewController.delegate = self
}
else if let destinationViewController = segue.destination as? SupplementContentViewController {
destinationViewController.supplement = self.detailed_content
destinationViewController.delegate = self
}
}
Finally, go back to second view controller, and set the value of delegate to what you want in viewWillDisappear method.
func viewWillDisappear(_ animated: Bool) {
self.main_content = contentTextView.text
delegate?.updateMaincontent(main_content: contentTextView.text)
}
How can I pass data back from a PopoverViewController to the main view controller on an iPhone?
I know I'm doing something terribly wrong but I cannot figure it out.
Here is the code:
PopoverViewController.swift
protocol PopoverViewControllerDelegate {
func messageData(data: AnyObject)
}
class PopoverViewController: UIViewController {
#IBOutlet weak var inputMessage: UITextField!
var delegate: PopoverViewControllerDelegate?
#IBAction func sendData(sender: AnyObject) {
if inputMessage.text != ""{
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
self.delegate?.messageData(inputMessage.text!)
}
}
}
Main ViewController.swift:
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate, PopoverViewControllerDelegate {
#IBOutlet weak var showData: UILabel!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// popover segue
if segue.identifier == "popoverSegue" {
let popoverViewController = segue.destinationViewController
popoverViewController.popoverPresentationController!.delegate = self
}
// code to comunicate with data in popoverViewController
let pvc = storyboard?.instantiateViewControllerWithIdentifier("popoverViewController") as! PopoverViewController
pvc.delegate = self
self.presentViewController(pvc, animated:false, completion:nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
func messageData(data: AnyObject) {
self.showData.text = "\(data)"
}
}
With the code above I can pass data back to the main view controller without a problem, the issue is that the popover doesn't work, it just acts like a regular ViewController occupying the whole screen.
The funny thing is that if I comment the following line of code the popover works but I can no longer pass data back, I can see the popover but the passing data stops working.
// if I comment this line
self.presentViewController(pvc, animated:false, completion:nil)
I don't get any errors, one just stops working.
Any suggestions?
Thanks a lot
In prepareForSegue, the destinationViewController is your PopoverViewController. You need to cast it to that and set the delegate on that so that you can pass back data, and you need to set the popoverPesentationController?.delegate as well. You don't need the rest of the code in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// popover segue
if segue.identifier == "popoverSegue" {
let popoverViewController = segue.destinationViewController as! PopoverViewController
popoverViewController.delegate = self
popoverViewController.popoverPresentationController?.delegate = self
}
}
I am pretty new to SWIFT coding. My intention is to pass 2 arrays with values from Viewcontroller1 to Viewcontroller2. But it returns me nil value in Viewcontroller2. Can someone advise me please?
Here is the partial code in ViewController1.
#IBAction func solve(sender: AnyObject) {
//pass information to the nextviewcontroller
func prepareForSegue ( segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "Solve") {
var svc = segue!.destinationViewController as ViewController2
svc.toPass = self.force
svc.toPass2 = stiffness
}
}
Here is the partial code in ViewController2.
class ViewController2: UITableViewController {
var toPass:[String]!
var toPass2:[String]!
override func viewDidLoad() {
super.viewDidLoad()
println(self.toPass)
println(self.toPass2)
// Do any additional setup after loading the view.
}
The full code can be found in here. https://github.com/cherrythia/SWIFTpassingarrays/blob/master/README.md
I have created project similar to yours (using your github link) and #Sebastian Wramba is correct. You have to separate these two functions:
#IBAction func solve_pressed(sender: AnyObject) {
self.performSegueWithIdentifier("Solve", sender: sender)
}
override func prepareForSegue ( segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "Solve") {
var svc = segue.destinationViewController as ViewController2
svc.toPass = self.force
svc.toPass2 = stiffness
}
}
Okay, solved (pun intended). You have to give your segue identifier, in this particular case, "Solve". In your first view controller, select push to View Controller2, go to the fourth tab and set identifier to "Solve".