How to get Data in a Viewcontroller ?

Hi,

I am having 4 ViewControllers and navigated to fourth viewcontroller by pushing from first to second and second to third and third to fourth.

From fouth viewcontroller i need to pass a data to second viewcontroller.

How to implement this?

Accepted Reply

1. Delegation is a way to do it.


Let's call your ViewControllers classes VC1, VC2, VC3, VC4.

Imagine you want to pass a String to VC2, to update a UITextField


One complexity is that you don't go directly from VC2 to VC4, but through VC3.


Declare a protocol:

protocol delegate_transferData {
    func writeInVC2(text: String)
}


In VC4, you create a delegate property :

I you want to send data when clicking a button:


class VC4: UIViewController {
    var delegate: delegate_transferData?

    @IBAction func writeDataToVC2(_ sender: UIButton) {
  
        let textToWrite = "I write this to VC2"
        delegate?.writeInVC2(text: textToWrite)
    }

}


In VC2, you implement the delegate func and will pass the delegate reference ; because you don't go directly to VC4, you'll first pass this reference to VC3:


class VC2: UIViewController, delegate_transferData {

    @IBOutlet weak var text1: UITextField!

    func writeInVC2(text: String) {
        text1.text = text
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? VC3 {
            destination.temporaryDelegate = self     // That's the complexity: to keep delegate in VC3 for use later in VC4
        }
    }
}

And in VC3


class VC3: UIViewController {
    var temporaryDelegate: delegate_transferData?

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? VC4 {
            destination.delegate = temporaryDelegate     // Now we get VC2 as delegate in VC4
        }
    }
}


---------

2. Another way would be to declare at the global scope a var to store the data you want to transmit


var dataToSend: String?


And set it in VC4 and reuse in VC2


------------

EDITED

-----------

3. A 3rd way, if you are in a NavigationController,

use property of the navigationController

var viewControllers: [UIViewController]


When in VC4, calling viewControllers[1] gives a reference to VC2 ; then you can access any property of it (this works because Navigation controllers keeps the stack of VC you come from ; however, you could not use this method to write ahead fromVC1 to VC3 for instance).

For instance, to copy a text from a UITectField in VC4 directly in VC2 when clicking the UIButton


class ViewController4: UIViewController {

    @IBOutlet weak var textToWrite: UITextField!
   
    override func viewDidLoad() {
        super.viewDidLoad()
    }
   
    @IBAction func writeToVC2(_ sender: UIButton) {
       
        let text = textToWrite.text
        if let vc2 = self.navigationController?.viewControllers[1] as? ViewController2 {
           vc2.labelToSetInVC2.text = text
        }
     }
   
}

Replies

1. Delegation is a way to do it.


Let's call your ViewControllers classes VC1, VC2, VC3, VC4.

Imagine you want to pass a String to VC2, to update a UITextField


One complexity is that you don't go directly from VC2 to VC4, but through VC3.


Declare a protocol:

protocol delegate_transferData {
    func writeInVC2(text: String)
}


In VC4, you create a delegate property :

I you want to send data when clicking a button:


class VC4: UIViewController {
    var delegate: delegate_transferData?

    @IBAction func writeDataToVC2(_ sender: UIButton) {
  
        let textToWrite = "I write this to VC2"
        delegate?.writeInVC2(text: textToWrite)
    }

}


In VC2, you implement the delegate func and will pass the delegate reference ; because you don't go directly to VC4, you'll first pass this reference to VC3:


class VC2: UIViewController, delegate_transferData {

    @IBOutlet weak var text1: UITextField!

    func writeInVC2(text: String) {
        text1.text = text
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? VC3 {
            destination.temporaryDelegate = self     // That's the complexity: to keep delegate in VC3 for use later in VC4
        }
    }
}

And in VC3


class VC3: UIViewController {
    var temporaryDelegate: delegate_transferData?

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? VC4 {
            destination.delegate = temporaryDelegate     // Now we get VC2 as delegate in VC4
        }
    }
}


---------

2. Another way would be to declare at the global scope a var to store the data you want to transmit


var dataToSend: String?


And set it in VC4 and reuse in VC2


------------

EDITED

-----------

3. A 3rd way, if you are in a NavigationController,

use property of the navigationController

var viewControllers: [UIViewController]


When in VC4, calling viewControllers[1] gives a reference to VC2 ; then you can access any property of it (this works because Navigation controllers keeps the stack of VC you come from ; however, you could not use this method to write ahead fromVC1 to VC3 for instance).

For instance, to copy a text from a UITectField in VC4 directly in VC2 when clicking the UIButton


class ViewController4: UIViewController {

    @IBOutlet weak var textToWrite: UITextField!
   
    override func viewDidLoad() {
        super.viewDidLoad()
    }
   
    @IBAction func writeToVC2(_ sender: UIButton) {
       
        let text = textToWrite.text
        if let vc2 = self.navigationController?.viewControllers[1] as? ViewController2 {
           vc2.labelToSetInVC2.text = text
        }
     }
   
}

Thanks a lot Claude31.

Which method did you chose ?

Hi Claude31,

sorry for late reply.

I used method1.


Thanks