简体   繁体   中英

Protocol Delegate not passing data as expected [Swift5]

I have created simple Protocol Delegate to pass data from One View Controller to Second View Controller - but data seems to be not carried across?

Details: First View Controller have a textField where I type my data (String) to be passed to Second VC. I also have a button with Action to trigger transition to Second View Controller. Second View Controller comes up but data from First View Controller does not show up - expected behaviour was for the Label in Second VC to be updated with my data from First VC. I also have created a segue from Button on FVC to SVC with the identifier ' sendDataIdentifier '.

What I'm doing wrong?

Code and screenshots below:

First View Controller

import UIKit

protocol SendDataDelegte {
    func sendData(data: String)
}

class FirstViewController: UIViewController {

    var delegate: SendDataDelegte? = nil

    @IBOutlet weak var dataCaptured: UITextField!

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

    @IBAction func sendDataButton(_ sender: Any) {
        let dataToBeSent = self.dataCaptured.text
        self.delegate?.sendData(data: dataToBeSent!)
    }
}

Second View Controller

import UIKit

class SecondViewController: UIViewController, SendDataDelegte {

    @IBOutlet weak var dataRetrived: UILabel!
    @IBAction func closeButton(_ sender: Any) {
         dismiss(animated: true, completion: nil)
    }

    func sendData(data: String) {
        self.dataRetrived.text = data
    }

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

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "sendDataIdentifier" {
            let firstVC: FirstViewController = segue.destination as! FirstViewController
            firstVC.delegate = self
        }
    }
}

在此处输入图像描述

You have it the wrong way around.

You don't need a delegate pattern in this instance. You need to implement prepare(for segue) in the first view controller and just pass the data to the destination view controller.

prepare(for segue) isn't called in the destination view controller and the delegate property will be nil in the first view controller because nothing is setting it.

class FirstViewController: UIViewController {

    @IBOutlet weak var dataCaptured: UITextField!

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

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let dest = segue.destination as? SecondViewController {
            dest.text = self.dataCaptured.text
        }
    }
}

class SecondViewController: UIViewController {

    @IBOutlet weak var dataRetrived: UILabel!
    var text: String?
    @IBAction func closeButton(_ sender: Any) {
         dismiss(animated: true, completion: nil)
    }

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

    override func viewWillAppear(_ animated:Bool) {
        super.viewWillAppear(animated)
        self.dataRetrieved.text = text
    }
}

To push data forward, you can use present method

And to send data backward use delegate.

Example:

First Screen

import UIKit

protocol SendDataDelegte: class {
    func sendData(data: String)
}


class FirstViewController: UIViewController, SendDataDelegte {
    
    var dataCaptured: UITextField = {
        let txt = UITextField()
        txt.translatesAutoresizingMaskIntoConstraints = false
        txt.backgroundColor = .lightGray
        return txt
    }()
    
    var sendDataButton: UIButton = {
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.backgroundColor = .lightGray
        return btn
    }()

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

    @objc func sendDataButtonAction() {
        let dataToBeSent = self.dataCaptured.text
        let vc = SecondViewController()
        vc.delegate = self
        vc.getDataLabel.text = dataToBeSent
        vc.modalPresentationStyle = .popover
        present(vc, animated: true, completion: nil)
    }
    
    func sendData(data: String) {
        sendDataButton.setTitle(data, for: .normal)
    }
    
    func setupUI() {
        view.backgroundColor = .blue
        view.addSubview(dataCaptured)
        dataCaptured.widthAnchor.constraint(equalToConstant: 200).isActive = true
        dataCaptured.heightAnchor.constraint(equalToConstant: 100).isActive = true
        dataCaptured.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        dataCaptured.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        
        view.addSubview(sendDataButton)
        sendDataButton.setTitle("Send Data", for: .normal)
        sendDataButton.titleColor(for: .normal)
        sendDataButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
        sendDataButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
        sendDataButton.topAnchor.constraint(equalTo: dataCaptured.bottomAnchor, constant: 50).isActive = true
        sendDataButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        
        sendDataButton.addTarget(self, action: #selector(sendDataButtonAction), for: .touchUpInside)
    }
}

Second Screen

import UIKit

class SecondViewController: UIViewController {
    
    weak var delegate: SendDataDelegte?
    
    var getDataLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        return lbl
    }()

    var dataCaptured: UITextField = {
        let txt = UITextField()
        txt.translatesAutoresizingMaskIntoConstraints = false
        txt.backgroundColor = .lightGray
        return txt
    }()
    
    var sendDataButton: UIButton = {
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.backgroundColor = .lightGray
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupUI()
    }
    
    @objc func sendDataButtonAction() {
        let string = dataCaptured.text!
        delegate?.sendData(data: string)
        dismiss(animated: true, completion: nil)
    }
    
    func setupUI() {
        view.backgroundColor = .yellow
    
        view.addSubview(getDataLabel)
        getDataLabel.backgroundColor = .lightGray
        getDataLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
        getDataLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
        getDataLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
        getDataLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
 
        view.addSubview(dataCaptured)
        dataCaptured.widthAnchor.constraint(equalToConstant: 200).isActive = true
        dataCaptured.heightAnchor.constraint(equalToConstant: 100).isActive = true
        dataCaptured.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        dataCaptured.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        
        view.addSubview(sendDataButton)
        sendDataButton.setTitle("Send Data", for: .normal)
        sendDataButton.titleColor(for: .normal)
        sendDataButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
        sendDataButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
        sendDataButton.topAnchor.constraint(equalTo: dataCaptured.bottomAnchor, constant: 50).isActive = true
        sendDataButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        
        sendDataButton.addTarget(self, action: #selector(sendDataButtonAction), for: .touchUpInside)
    }
    

}

When we call present method on first screen, we send data to second screen's label and assign delegate to self.

When we tap button on second screen, we call delegate method and send text to button title on first screen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM