-->

Trying to understand protocol/delegates in Swift

2020-02-08 18:27发布

问题:

I'm new to programming & Swift and I am trying to understand how to pass data between two view controllers (no segue) with protocols and delegates.

I have a View Controller (VIEW A) which has a text field and button. When the user hits that button, it should then show that text in a label in another View Controller (VIEW B).

I cannot get the label to show the text - I would appreciate an explanation of what is required to make this work.

Thanks so much!

import UIKit

            protocol sendNameToViewB {

                func showNameLabel(name:String)
            }

            class ViewA: UIViewController {

                var delegate: sendNameToViewB?

                @IBOutlet weak var textField: UITextField!

                @IBAction func addButton(sender: AnyObject) {
                    delegate?.showNameLabel(textField.text)

                }
                 override func viewDidLoad() {
                    super.viewDidLoad()

                    // Do any additional setup after loading the view, typically from a nib.
                }
                override func didReceiveMemoryWarning() {
                    super.didReceiveMemoryWarning()
                    // Dispose of any resources that can be recreated.
                }


            }

            class ViewB: UIViewController, sendNameToViewB {

                @IBOutlet weak var theLabel: UILabel!

                func showNameLabel(name: String) {
                    theLabel.text = name
                }
            }

回答1:

First, a note: Your names for view controllers should include "ViewController" in the name. There is an entirely different collection of classes that inherit from UIView. Naming a View Controller just ViewA makes it look like your class is just a view instead of a view controller. Views are in an entirely different layer of your application.

Now, to pass data to another object, your first requirement is to have a reference between them. This reference can be setup in either direction.

One possibility is to have ViewControllerA keep a reference to ViewControllerB. Through this reference, ViewControllerA can call a method on ViewControllerB when the button is pressed which takes that data you want to pass as an argument.

class ViewControllerA: UIViewController {
    @IBOutlet weak var viewControllerB: ViewControllerB!

    @IBAction func addButton(sender: AnyObject) {
        self.viewControllerB.showNameLabel(textField.text)
    }
}

The other possibility, is to use a delegate pattern like your title suggests. This would involve ViewControllerB having a reference to ViewControllerA. Preferably, this would not be with direct knowledge of the ViewControllerA class, but instead through a protocol. The protocol would define a method that returns the data you want to "pass" to ViewControllerB. That way, ViewContollerB can call the protocol method on its "delegate" (which would happen to be ViewControllerA) to get the data it needs.

protocol ViewControllerBDelegate {
    func requiredText() -> String
}

class ViewControllerB: UIViewController {
    @IBOutlet weak var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        if let actualDelegate = self.delegate {
            self.theLabel.text = actualDelegate.requiredText()
        }
    }
}

Which method you choose really depends on what you need in this circumstance. The delegate pattern is better to keep your objects less coupled together, but if you are already needing to "trigger" things to happen on ViewControllerB from ViewControllerA then the more direct method is probably required.