Swift:跨多屏幕收集文本框数据的更简洁实现方案
嘿,看你现在在做多页面UITextField的数据收集,用prepare(for:sender:)来把文本框内容存到模型里对吧?我来给你捋捋当前实现的情况,还有几个实用的优化方向~
首先先把你提供的代码片段补全展示下:
class MyViewController: UIViewController { @IBOutlet weak var textField: UITextField! var foo: MyModel = MyModel() // 首次创建模型实例 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.destination is AnotherViewController { self.foo.column1 = textField.text ?? "" // 补全合理的默认值 // 这里大概率还要把模型传递给下一个页面 } } }
当前实现的优缺点
- 优点:逻辑直观,直接在页面跳转前完成数据收集,符合Segue的常规使用场景
- 潜在问题:
- 要是后续页面需要修改模型数据,来回跳转时容易出现数据不同步的问题(比如每个页面都持有独立的模型实例)
- 页面变多后,每个页面都要写类似的
prepare代码,冗余度很高 - 缺少输入校验,空值或者格式错误的内容直接存入模型,可能给后续逻辑埋坑
几个优化方案
方案1:单例全局模型(适合简单线性流程)
如果你的页面流程是单向线性的,不需要复杂状态管理,可以把MyModel做成单例,让所有页面共享同一个实例,省去页面间传递的麻烦:
// 改造MyModel为单例 class MyModel { static let shared = MyModel() var column1: String = "" var column2: String = "" // 其他需要收集的字段... } // 在MyViewController中使用 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.destination is AnotherViewController { // 先做输入清洗,去掉首尾空格 let inputText = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" // 加个简单校验 guard !inputText.isEmpty else { // 提示用户输入内容,比如给文本框加个抖动动画 textField.shake() return } MyModel.shared.column1 = inputText } }
方案2:闭包回调(适合需要反向传值的场景)
如果下一个页面可能要修改数据,或者你不想用单例,可以给目标ViewController加回调闭包,在页面消失时回传更新后的模型:
// AnotherViewController的改造 class AnotherViewController: UIViewController { @IBOutlet weak var anotherTextField: UITextField! var currentModel: MyModel! var onDataUpdated: ((MyModel) -> Void)? override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 收集当前页面的文本框数据 currentModel.column2 = anotherTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" // 通过闭包回传更新后的模型 onDataUpdated?(currentModel) } } // MyViewController的prepare方法修改 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let destVC = segue.destination as? AnotherViewController else { return } // 先收集当前页面的数据 foo.column1 = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" // 传递模型给下一个页面 destVC.currentModel = foo // 设置回调,接收更新后的模型 destVC.onDataUpdated = { updatedModel in self.foo = updatedModel // 这里可以做后续操作,比如保存到本地或者提交服务器 } }
方案3:Coordinator模式(适合复杂页面流程)
如果你的页面流程有分支跳转、模态弹窗等复杂场景,用Coordinator模式可以把页面跳转和数据管理逻辑从ViewController中抽离,让ViewController只专注于UI展示:
// 定义Coordinator协议 protocol Coordinator: AnyObject { func start() func navigateToAnotherViewController(with model: MyModel) } // 实现具体的Coordinator class MainCoordinator: Coordinator { var navigationController: UINavigationController var model: MyModel = MyModel() init(navigationController: UINavigationController) { self.navigationController = navigationController } func start() { let vc = MyViewController() vc.coordinator = self navigationController.pushViewController(vc, animated: true) } func navigateToAnotherViewController(with model: MyModel) { // 收集当前页面的数据 self.model.column1 = model.column1 let vc = AnotherViewController() vc.coordinator = self vc.model = self.model navigationController.pushViewController(vc, animated: true) } } // MyViewController的改造 class MyViewController: UIViewController { @IBOutlet weak var textField: UITextField! weak var coordinator: MainCoordinator? var model: MyModel = MyModel() // 跳转按钮的点击事件 @IBAction func nextButtonTapped(_ sender: UIButton) { model.column1 = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" coordinator?.navigateToAnotherViewController(with: model) } }
内容的提问来源于stack exchange,提问作者Tenten Ponce
相关产品推荐
相关产品推荐

