31

I am trying to transfer data from the textfield of one View Controller to the label from another.

How can I call the View Controller instance from the code of the other View Controller? I'm working with storyboards thus I never created an instance of the View Controllers in the code? Are the instances automatically created? And what name do they have?

Thanks for your help!

McLawrence
  • 4,975
  • 7
  • 39
  • 51
  • in ViewController A, you create ViewController B. Now you have access to ViewController B, so just set a property or send a message to ViewController B. Now you can push ViewController B onto the navigation controller. – John Aug 08 '14 at 13:26
  • possible duplicate of [Passing data between View Controllers using Segue](http://stackoverflow.com/questions/20017026/passing-data-between-view-controllers-using-segue) – Robotic Cat Aug 08 '14 at 13:58

3 Answers3

21

1. If the view controller containing the textfield can call (with a segue) the view controller containing the label...

Add a new Cocoa Touch class file in your project, name it FirstViewController and set the following code in it:

import UIKit

class FirstViewController: UIViewController {
    
    @IBOutlet weak var textField: UITextField! // FIXME: link this to the UITextField in the Storyboard!!!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        let controller = segue.destinationViewController as! SecondViewController
        controller.text = textField.text
    }
    
}

Add a new Cocoa Touch class file in your project, name it SecondViewController and set the following code in it:

import UIKit

class SecondViewController: UIViewController {
    
    var text: String?
    @IBOutlet weak var label: UILabel! // FIXME: link this to the UILabel in the Storyboard!!!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label.text = text
    }
    
}

In the Storyboard, embed the first view controller in a UINavigationController. Link the first view controller to the second with a UIButton or a UIBarButtonItem. Set the name of the first view controller to FirstViewController and the name of the second view controller to SecondViewController. Create a UITextField in the first view controller. Create a UILabel in the second view controller. Link the textfield and the label to their respective declarations in FirstViewController and SecondViewController.


2. If the view controller containing the label can call (with a segue) the view controller containing the textfield...

Here, this is a perfect protocol/delegate case. You may find a lot of stuff on StackOverflow dealing with this. However, here is a rough example.

Add a new Cocoa Touch class file in your project, name it FirstViewController and set the following code in it:

import UIKit

class FirstViewController: UIViewController, DetailsDelegate {
    
    @IBOutlet weak var label: UILabel! // FIXME: link this to the UILabel in the Storyboard
    
    func updateLabel(withString string: String?) {
        label.text = string
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        let controller = segue.destinationViewController as! SecondViewController
        controller.delegate = self
    }
    
}

Add a new Cocoa/Cocoa Touch class file in your project, name it SecondViewController and set the following code in it:

import UIKit

protocol DetailsDelegate: class {
    func updateLabel(withString string: String?)
}

class SecondViewController: UIViewController {
    
    weak var delegate: DetailsDelegate?
    @IBOutlet weak var textField: UITextField! // FIXME: link this to the UITextField in the Storyboard
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        
        delegate?.updateLabel(withString: textField.text)
    }

}

In the Storyboard, embed the first view controller in a UINavigationController. Link the first view controller to the second with a UIButton or a UIBarButtonItem. Set the name of the first view controller to FirstViewController and the name of the second view controller to SecondViewController. Create a UILabel in the first view controller. Create a UITextField in the second view controller. Link the textfield and the label to their respective declarations in FirstViewController and SecondViewController.

Community
  • 1
  • 1
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
  • 3
    Is there a way to achieve something like this without segue ? – Ilir V. Gruda Jun 02 '15 at 20:21
  • Hi. I have this same problem. But am not using storyboard in my case. Am using xib. So how do i send the delegate reference from first to second view controller without using segue? – Mano Jan 30 '17 at 13:04
16

Imanou Petit and Oscar Swanros already answered correctly. However there is an alternative which is rather "hacky" that I had to use to transfer data between 2 view controllers without a segue connecting them.

To obtain the root view controller of your app you can do:

UIApplication.sharedApplication().windows[0].rootViewController

From there you can get any view controller you want. For instance, if you want the second child view controller of the root view controller then you would do:

let viewController = UIApplication.sharedApplication().windows[0].rootViewController?.childViewControllers[1] as? YourViewController
viewController?.yourProperty = newValue

Keep in mind that this approach is rather "hacky" and probably violates the best coding practices.

João Neves
  • 944
  • 1
  • 13
  • 18
  • With a correctly answered question, why provide something rather "hacky" which probably violates the best coding practices? – Craig B Mar 27 '18 at 01:05
6

You need to create a Segue between View Controllers:

  1. On your Storyboard, select ViewController A.
  2. While holding the Control, click ViewController A, drag and drop the blue line to ViewController B. If ViewController A is embedded in a NavigationController, select "show" from the menu that appears when you let go. Otherwise, select "present modally."
  3. Select the Segue on your Storyboard, and on the Utilities Panel, go to the Attributes Inspector and assign an Identifier for your segue (e.g.: "DetailSegue").

Now, when you want to trigger the segue on ViewController A, you just need to call (maybe on the tap of a button):

@IBAction func buttonTapped() {
    self.performSegueWithIdentifier("DetailSegue", sender: self)
}

To pass a value to ViewController B, override the prepareForSegue:sender method on ViewController A:

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if segue.identifier == "DetailSegue" {
        var viewControllerB = segue.destinationViewController as ViewControllerB
        viewControllerB.text = self.textField.text
    }
}

Pretty straightforward.

Note that for this to work, your ViewController B class should look something like this:

class ViewControllerB: UIViewController {
    ver label = UILabel(...)
    var text: String? 

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = text!
    }
}

Hope this helps.

Oscar Swanros
  • 19,767
  • 5
  • 32
  • 48
  • 1
    How do we create a property instance of SecondViewController in FirstViewController with Swift – Nassif Apr 14 '15 at 08:27
  • Thanks! I was stuck about how to make the segue in storyboard without having a button in viewController1 to attach it from – Ann Taylor Mar 15 '20 at 02:59