为何需两次调用协议函数才能生效?iOS代理模式问题求助
iOS 协议-代理功能问题修复方案
核心问题分析
你的代码存在几个关键错误,导致必须两次调用协议方法才能生效:
- SecondViewController错误遵守了自身定义的协议,还在返回按钮点击时自行调用协议方法,完全没必要
- FirstViewController中额外实例化了SecondViewController对象,这个实例和segue跳转创建的VC不是同一个,导致数据无法正确传递
- FirstViewController的协议方法实现逻辑错误,没有直接更新UI,反而去读取错误实例的属性
分步修正
1. 修正SecondViewController
移除VC对自身协议的遵守,删除多余的协议方法实现,只保留代理调用逻辑:
import UIKit protocol SecondViewControllerDelegate { func changeLabelText(name: String) } class SecondViewController: UIViewController { var delegate: SecondViewControllerDelegate? @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var backButton: UIButton! @IBAction func backButtonPressed(_ sender: UIButton) { let inputName = nameTextField.text ?? "" // 只需要调用代理的方法传递数据 delegate?.changeLabelText(name: inputName) dismiss(animated: true) } override func viewDidLoad() { super.viewDidLoad() } }
2. 修正FirstViewController
删除无用的SecondViewController实例,正确实现协议方法并直接更新Label:
import UIKit class FirstViewController: UIViewController, SecondViewControllerDelegate { @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var button: UIButton! // 移除多余的secondVC实例(和segue创建的不是同一个对象) // let secondVC = SecondViewController() // 协议方法直接用传递过来的参数更新Label func changeLabelText(name: String) { nameLabel.text = name } @IBAction func buttonPressed(_ sender: UIButton) { performSegue(withIdentifier: "goToSecondVC", sender: self) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destinationVC = segue.destination as? SecondViewController destinationVC?.delegate = self } override func viewDidLoad() { super.viewDidLoad() // 移除错误的初始化赋值(secondVC是无效实例) // nameLabel.text = secondVC.enteredName } }
关键修改说明
- SecondViewController无需遵守自身协议:协议是用来定义外部对象需要实现的方法,VC本身只需要持有代理对象并触发方法即可
- 删除多余的VC实例:segue跳转时系统会自动创建SecondViewController实例,你自行实例化的对象和界面上的VC完全无关,会导致数据不互通
- 协议方法直接更新UI:代理方法的核心作用就是把SecondVC的数据传递给FirstVC,直接在方法里用参数更新Label即可,无需额外中转
内容的提问来源于stack exchange,提问作者flolopi
相关产品推荐
相关产品推荐

