Swift4中通过代理从第二个VC传值到第一个VC,TextField不显示数据求助
Swift4协议代理传值后TextField不显示数据的排查与解决
我太懂这种糟心的感觉了——明明通过协议代理从第二个ViewController拿到数据了,可第一个VC的TextField就是纹丝不动,数据在手却UI不更新,真的让人头大!咱们一步步来揪出问题所在:
一、先确认代理有没有正确“绑定”
虽然你说数据已经接收了,但还是先确认这一步:在第一个VC跳转到第二个VC的时候,有没有把第二个VC的delegate设为当前的第一个VC?这是协议代理能工作的核心前提,很多人容易漏这一步!
比如第一个VC里跳转的代码应该是这样的:
@IBAction func goToSecondVC(_ sender: UIButton) { let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController secondVC.delegate = self // 这行必须加!把第一个VC设为第二个VC的代理 navigationController?.pushViewController(secondVC, animated: true) }
二、重点:UI更新必须在主线程!
这是最常见的坑!如果你的协议方法是在后台线程触发的(比如第二个VC里在异步任务里调用了代理方法),那直接更新TextField是无效的——iOS规定所有UI操作必须在主线程执行。
所以在第一个VC的协议实现方法里,一定要把更新TextField的代码包在DispatchQueue.main.async里:
// 你实现的协议方法 func sendDataToFirstVC(data: String) { valueSentFromSecondViewController = data // 强制回到主线程更新UI DispatchQueue.main.async { self.myTextField.text = self.valueSentFromSecondViewController } }
三、检查TextField的IBOutlet是否真的关联上了
有时候看起来IBOutlet已经拖好了,但实际关联可能断了。你可以在viewDidLoad里加一行测试代码验证:
override func viewDidLoad() { super.viewDidLoad() myTextField.text = "测试一下" // 运行看看TextField会不会显示这句话 }
如果测试文字也不显示,那就是IBOutlet没正确关联,重新在Storyboard里拖一次关联就行。
四、确认协议触发时,第一个VC的视图已经加载完成
如果第二个VC在第一个VC的视图还没完全加载好的时候就调用了代理方法,那myTextField可能还没初始化完成,这时候赋值也不会生效。
这种情况可以把更新逻辑放到viewDidAppear里,确保视图出现时再更新:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let receivedValue = valueSentFromSecondViewController { myTextField.text = receivedValue } }
给你一个完整的可运行参考代码
协议定义(可以单独建一个.swift文件,或者写在第二个VC上方)
protocol MyProtocol: AnyObject { func sendDataToFirstVC(data: String) }
第二个ViewController代码
import UIKit class SecondViewController: UIViewController { // 代理要用weak修饰,避免循环引用 weak var delegate: MyProtocol? @IBOutlet weak var inputTextField: UITextField! @IBAction func sendDataBack(_ sender: UIButton) { guard let inputText = inputTextField.text else { return } // 回到主线程调用代理方法,从根源避免UI线程问题 DispatchQueue.main.async { self.delegate?.sendDataToFirstVC(data: inputText) } navigationController?.popViewController(animated: true) } }
第一个ViewController代码
import UIKit class FirstViewController: UIViewController, MyProtocol { var valueSentFromSecondViewController: String? @IBOutlet weak var myTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() // 可以在这里测试IBOutlet是否正常 // myTextField.text = "测试" } @IBAction func goToSecondVC(_ sender: UIButton) { let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController secondVC.delegate = self navigationController?.pushViewController(secondVC, animated: true) } // 实现协议方法 func sendDataToFirstVC(data: String) { valueSentFromSecondViewController = data DispatchQueue.main.async { self.myTextField.text = self.valueSentFromSecondViewController } } }
内容的提问来源于stack exchange,提问作者Ahtazaz khan
相关产品推荐
相关产品推荐

