从Xib弹窗UIView的TextField传数据到ViewController遇阻求助
弹窗UIView数据回传问题:TextField代理中delegate为nil,保存按钮点击时name为空
在获取弹窗UIView的用户输入数据时遇到两个异常:
- TextFieldDelegate的
textFieldDidEndEditing方法中,能正确获取并打印输入的name值,但打印delegate为nil,导致无法调用saveName回传数据; - 点击保存按钮时,能正常打印delegate(指向ViewController),但打印name为空,回传的也是空值。
需求是将用户输入的name变量正确传回ViewController。
ViewController 代码
class ViewController: UIViewController { var popUp: PopUp? override func viewDidLoad() { super.viewDidLoad() } } extension ViewController: PopUpDelegate { func saveName(_ name: String) { print(name) // 测试打印 } @IBAction func popUpButton(_ sender: UIButton) { self.popUp = PopUp(frame: self.view.frame, sender: self) self.view.addSubview(popUp!) } }
PopUp 代码
class PopUp: UIView { @IBOutlet weak var textOutlet: UITextField! var delegate: PopUpDelegate? var name = "" override func awakeFromNib() { super.awakeFromNib() textOutlet.delegate = self } required init?(coder: NSCoder) { super.init(coder: coder) } init(frame: CGRect, sender: PopUpDelegate) { super.init(frame: frame) xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)) self.delegate = sender } func xibSetup(frame: CGRect) { let view = loadXib() view.frame = frame addSubview(view) } func loadXib() -> UIView { let bundle = Bundle(for: type(of: self)) let nib = UINib(nibName: "PopUp", bundle: bundle) let view = nib.instantiate(withOwner: self, options: nil).first as? UIView return view! } @IBAction func cancelButton(_ sender: UIButton) { self.removeFromSuperview() } @IBAction func saveButton(_ sender: UIButton) { print(delegate) // 打印ViewController print(name) // 打印空字符串 delegate?.saveName(name) // 回传空值 self.removeFromSuperview() } } extension PopUp: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField.text != "" { textField.endEditing(true) return true } else { textField.placeholder = "name required*" } return true } func textFieldDidEndEditing(_ textField: UITextField) { if textField.text != "" { name = textField.text! print(delegate) // 打印nil print(name) // 打印输入的文本 delegate?.saveName(name) // 无响应 } else { textField.placeholder = "name required*" } } } protocol PopUpDelegate { func saveName(_ name: String) }
问题根源与修复方案
问题1:textFieldDidEndEditing中delegate为nil
原因:通过nib.instantiate(withOwner: self, options: nil)加载XIB时,系统会额外创建一个PopUp实例作为XIB的owner,你设置delegate的是外层的PopUp实例,但XIB内部的TextField实际关联的是这个新创建的owner实例,它的delegate未被赋值,所以打印nil。
修复步骤:
- 在XIB中给根视图添加IBOutlet,命名为
contentView(确保根视图的class设置为PopUp); - 修改
loadXib方法,让XIB控件直接关联当前PopUp实例:
func loadXib() -> UIView { let bundle = Bundle(for: type(of: self)) let nib = UINib(nibName: "PopUp", bundle: bundle) nib.instantiate(withOwner: self, options: nil) return contentView }
- 调整
init(frame:sender:)的时序,先赋值delegate再加载XIB:
init(frame: CGRect, sender: PopUpDelegate) { super.init(frame: frame) self.delegate = sender xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)) }
问题2:保存按钮点击时name为空
原因:当前代码中name变量只有在textFieldDidEndEditing触发时才会被赋值,但用户可能直接点击保存按钮而不触发结束编辑,此时name还是初始空字符串。
修复步骤:
点击保存按钮时,直接从textOutlet获取最新文本,移除冗余的name变量:
@IBAction func saveButton(_ sender: UIButton) { guard let inputName = textOutlet.text, !inputName.isEmpty else { textOutlet.placeholder = "name required*" return } delegate?.saveName(inputName) self.removeFromSuperview() }
内容的提问来源于stack exchange,提问作者impLo
相关产品推荐
相关产品推荐

