buzzmind
buzzmind

Reputation: 109

How to achieve delegation between two ViewController use segue in swift?

enter image description here

I am little bit confuse abt delegation in swift. Say, if I want to pass text of textfield in BViewController to AViewController. (AViewController has a label but I did not put any text, so it shows nothing there) After user done the input and click the "LETS GO" button, text of label in AViewController should show the same text. I implement the code but it gives me some errors. Thanks.

code:

import UIKit

class AViewController: UIViewController, BViewDelegate {


    @IBOutlet weak var labelTextData: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()


    }

    func userDoneInput(textData: String) {
        labelTextData.text = textData
    }



}




import UIKit

protocol BViewDelegate{
    func userDoneInput(textData: String)
}

class BViewController: UIViewController {


    @IBOutlet weak var UserInputText: UITextField!
    var bViewDelegate: BViewDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()


    }


    @IBAction func LetsGo(_ sender: UIButton) {
       self.performSegue(withIdentifier: "ShowData", sender: self)

    }

    //use segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier  == "ShowData" {
            let destination = segue.destination as! AViewController
            destination.labelTextData.text = UserInputText.text

        }
    }

}

Upvotes: 1

Views: 2261

Answers (3)

Shehata Gamal
Shehata Gamal

Reputation: 100543

1- A shows

2- When you perform segue to B set delegate here ( this code inside A )

@IBAction func MoveToB (_ sender: UIButton) {
   self.performSegue(withIdentifier: "GoToB", sender: self)

}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier  == "GoToB" {
        let destination = segue.destination as! BViewController
        destination.bViewDelegate = self
    }
}

3- When you want to return from B to A ( This code inside B )

self.bViewDelegate?.userDoneInput(textData: UserInputText.text!)
self.dismiss(animated:true,completion:nil)

4- There should not be any segue from B to A

Upvotes: 3

Code Different
Code Different

Reputation: 93191

It's pretty simple:

Interface Builder Setup

A has a label that you can edit in B. There are two buttons that allow you to navigate back and forth. It's important that you don't Ctrl + click on the "Go back to A" button to segue to A. Doing so will add another controller to your hierarchy: A presents B which presents another A. Instead, B should dismiss itself to reveal the original A (see the code below).

IB setup

Code

//
// AViewController.swift
//
class AViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "gotoB", let bController = segue.destination as? BViewController {
            // Give B a chance to finish loading before using its outlets
            bController.loadViewIfNeeded()
            bController.textField.text = label.text
            bController.delegate = self
        }
    }
}

extension AViewController: BViewControllerDelegate {
    // B says that it has ended. We now update the label in A
    func bViewControllerDidEnd(_ controller: BViewController, textValue: String) {
        label.text = textValue
    }
}

//
// BViewController.swift
//
protocol BViewControllerDelegate {
    // For delegate methods, it's customary to pass in the object that triggers this delegate
    // (the BViewController), in case you need to make use of its other properties
    func bViewControllerDidEnd(_ controller: BViewController, textValue: String)
}

class BViewController: UIViewController {
    @IBOutlet weak var textField: UITextField!
    var delegate: BViewControllerDelegate?

    @IBAction func goBackToA(_ sender: Any) {
        // Tell the delegate that "I'm done"
        delegate?.bViewControllerDidEnd(self, textValue: textField.text!)

        // Dismiss B, not segue to another instance of A
        self.dismiss(animated: true)
    }
}

Upvotes: 0

andym
andym

Reputation: 67

Firstly, it's best practice not to use a segue to return from A to B (in fact, you are not returning at all, but rather putting a new instance of A over B). There are various options. Here are three:

  • Use an unwind segue.
  • If you presented B modally, then call B's dismiss function (your image suggests this is what you are doing but it is missing from the code).
  • If you showed B as part of a navigation controller then call B's navigationController's popViewController(animated:) method.

Before you present B from A, you need to set B's delegate property to be A (you are not doing this at the moment). Then you present B. Then when the user taps "LET'S GO" on B, simply call self.dismiss (or alternative - see options above), but also call self.delegate.userDoneInput(textData:).

Upvotes: 0

Related Questions