skip to Main Content

I need to pass a String and Array from my Third ViewController to my First ViewController directly using protocol/delegate, I have no problem doing it from VC 2 to VC 1 but I’m having a hard time with this. Also after clicking a button in my VC3 I need to go back to VC 1 and update the VC UI how would I do that? Would that have to be in viewdidload?
This in Swift UIKit and Storyboard

3

Answers


  1. What you need is unwind segue. Unwind segue will act like segue, only backward, popping, in this case, VC2. You can read here for more information.

    Updating data code would be put in a function similar to prepareToSegue() but for unwind segue in your VC1.
    Example of the function inside VC1:

    @IBAction func unwindToDestination(_ unwindSegue: UIStoryboardSegue) {
        switch unwindSegue.identifier {
        case SegueIdentifier.yourSegueIdentifier:
            let sourceVC = unwindSegue.source as! SourceVC
            dataToPass = sourceVC.dataToPass
            reloadData()
        default:
            break
        }
    }
    
    Login or Signup to reply.
  2. You need two protocols, and your firstVC and SecondVC have to conform those. When pushing new ViewController you need to give the delegate of that ViewController to self. On your third VC, when you click the button you need to call your delegate and pass your data to that delegate method, then repeat the same for other.

    For FirstVC

    protocol FirstProtocol: AnyObject {
        func firstFunction(data: String)
    }
    
    class FirstVC: UIViewController, FirstProtocol {
        
        weak var delegate: FirstProtocol?
    
        @IBAction func buttonClicked(_ sender: Any) {
            let secondVC = SecondVC()
            secondVC.delegate = self
            navigationController?.pushViewController(secondVC, animated: true)
        }
        
        func firstFunction(data: String) {
            navigationController?.popToRootViewController(animated: true)
            print(data)
        }
    }
    

    You handle your navigation from your root. For better experience you can use something like coordinator pattern to handle it.

    protocol SecondProtocol: AnyObject {
        func secondFunction(data: String)
    }
    
    class SecondVC: UIViewController, SecondProtocol {
        
        weak var delegate: FirstProtocol?
                
        @objc func buttonClicked() {
            let thirdVC = ThirdVC()
            thirdVC.delegate = self
            navigationController?.pushViewController(thirdVC, animated: true)
        }
        
        func secondFunction(data: String) {
            delegate?.firstFunction(data: data)
        }
    }
    

    Second VC is something that you just need to pass parameters.

    class ThirdVC: UIViewController {
        
        weak var delegate: SecondProtocol?
        
        @objc func buttonClicked() {
            delegate?.secondFunction(data: "data") // PASS YOUR ARRAY AND STRING HERE
        }
    }
    
    Login or Signup to reply.
  3. Here is a different approach that accomplishes what you described by performing a Present Modally segue directly from View Controller 3 to View Controller 1, and sharing the string and array values by way of override func prepare(for segue....

    In Main.storyboard, I set up 3 View Controllers, and have segues from 1 to 2, 2 to 3, and 3 to 1. These are Action Segues directly from the buttons on each VC, which is why you won’t see self.performSegue used inside any of the View Controller files. Here is the picture:
    storyboard layout image

    In the first view controller, variables are initialized (with nil values) that will hold a String and an Array (of type Int in the example, but it could be anything):

    import UIKit
    
    class FirstViewController: UIViewController {
        @IBOutlet weak var updatableTextLabel: UILabel!
        
        var string: String?
        var array: [Int]?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // These will only not be nil if we came here from the third view controller after pressing the "Update First VC" button there.
            // The values of these variables are set within the third View Controller's .prepare(for segue ...) method.
            // As the segue is performed directly from VC 3 to VC 1, the second view controller is not involved at all, and no unwinding of segues is necessary.
            if string != nil {
                updatableTextLabel.text = string
            }
            if let a = array {
                updatableTextLabel.text? += "nn(a)"
            }
        }
    }
    

    The second view controller doesn’t do anything except separate the first and third view controllers, so I didn’t include its code.

    The third view controller assigns the new values of the string and array inside prepare (this won’t be done unless you press the middle button first, to demonstrate both possible outcomes in VC 1). This is where your string and array get passed directly from 3 to 1 (skipping 2 entirely).

    import UIKit
    
    class ThirdViewController: UIViewController {
        var theString = "abcdefg"
        var theArray = [1, 2, 3]
        var passValuesToFirstVC = false
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        @IBAction func updateFirstVC(_ sender: UIButton) {
            passValuesToFirstVC = true
        }
        
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if passValuesToFirstVC && segue.identifier == "toFirst" {
                // Cast segue.destination (which on its own has type UIViewController, the superclass to all your custom View Controllers) to the specific subclass that your first View Controller belongs to
                let destinationVC = segue.destination as! FirstViewController
                // When your first view controller loads, it will receive these values for the 'string' and 'array' variables.  They replace the original 'nil' values these had in the FirstViewController definition.
                destinationVC.string = theString
                destinationVC.array = theArray
            }
        }
    }
    

    Note that there is an IBOutlet to the label on the first View Controller which contains the text to be updated.

    After visiting the third view controller, pressing the "Update First VC Text" button, and then performing the segue back to the first, here is how it will look:
    first view controller after update image

    This doesn’t address the part about protocols and delegates in your question (as I’m not sure how they’re being used in your program, and other answers have already addressed that), but it illustrates the method of transferring variables directly from one View Controller to another without unwinding segues or using the UINavigationController.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search