不使用Storyboard(无Segues)时Swift中ViewController间传数据及代理实现
嘿,我完全懂你现在的纠结——不用Storyboard的时候,ViewController之间传数据确实没Segue那么顺手,单例又褒贬不一,代理协议听起来靠谱但不知道怎么落地对吧?我来给你把这些理清楚,尤其是代理的实现步骤,再补充几个实用的替代方案。
先说说为什么单例传数据要谨慎
单例的问题在于它是全局共享的,一旦用它传业务数据,很容易让各个ViewController之间产生强耦合——比如多个页面都修改单例里的数据,你很难追踪到底是谁改的,调试起来头大。而且单例会一直驻留在内存里,如果是大数据对象,对内存也不友好。除非是全局配置这种几乎不会变的东西,不然传业务数据真的不推荐用单例。
不用Storyboard时,ViewController间数据传递的靠谱方案
1. 正向传数据:直接初始化传参(最简单安全)
如果是从A页面跳转到B页面,需要把数据从A传给B,根本不用复杂的东西——直接给B写个带参数的初始化方法就行。
比如B页面的代码:
class DetailViewController: UIViewController { // 要接收的数据模型 private let item: YourDataModel // 自定义初始化方法 init(with item: YourDataModel) { self.item = item super.init(nibName: nil, bundle: nil) // 纯代码初始化的话,nibName传nil } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") // 不用Storyboard的话,这个可以直接报错 } // 后续就可以直接用self.item了 }
然后在A页面里创建B并跳转:
class ListViewController: UIViewController { // 假设这里有个选中的数据项 private var selectedItem: YourDataModel! private func goToDetailPage() { let detailVC = DetailViewController(with: selectedItem) navigationController?.pushViewController(detailVC, animated: true) } }
这种方式最直接,数据流向清晰,而且完全是类型安全的,编译器会帮你检查参数是否正确,不会出现传错数据的情况。
2. 反向传数据:用代理协议(适合复杂交互)
如果是B页面操作完数据,要把结果传回A页面,这时候代理协议就是标准解决方案了。步骤很清晰:
第一步:在B页面定义代理协议
// 定义协议,用AnyObject限制只能类类型遵守(避免结构体) protocol DetailViewControllerDelegate: AnyObject { // 声明传递数据的方法,把当前VC和数据都传回去,方便A页面识别来源 func detailViewController(_ vc: DetailViewController, didFinishUpdating item: YourDataModel) // 可选:如果需要处理取消操作,再加一个方法 func detailViewControllerDidCancel(_ vc: DetailViewController) }
第二步:在B页面添加弱引用的代理属性
一定要用weak,不然会导致A和B互相持有,产生内存泄漏:
class DetailViewController: UIViewController { weak var delegate: DetailViewControllerDelegate? private var currentItem: YourDataModel! // 自定义初始化方法接收初始数据 init(with item: YourDataModel) { self.currentItem = item super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 比如用户点击保存按钮时,调用代理方法 @objc private func saveTapped() { // 假设已经修改了currentItem delegate?.detailViewController(self, didFinishUpdating: currentItem) // 关闭页面 navigationController?.popViewController(animated: true) } @objc private func cancelTapped() { delegate?.detailViewControllerDidCancel(self) navigationController?.popViewController(animated: true) } }
第三步:在A页面遵守协议并设置代理
class ListViewController: UIViewController, DetailViewControllerDelegate { // ... private func goToDetailPage() { let detailVC = DetailViewController(with: selectedItem) detailVC.delegate = self // 设置代理 navigationController?.pushViewController(detailVC, animated: true) } // 实现代理方法 func detailViewController(_ vc: DetailViewController, didFinishUpdating item: YourDataModel) { // 在这里处理传回的数据,比如更新列表 updateList(with: item) } func detailViewControllerDidCancel(_ vc: DetailViewController) { // 处理取消操作,比如刷新状态或者什么都不做 } }
3. 反向传数据:用闭包(轻量简洁)
如果只是简单的回调,比如只需要传一个数据或者通知取消,闭包比代理更简洁,不用写协议和遵守方法。
在B页面定义闭包属性
class DetailViewController: UIViewController { private var currentItem: YourDataModel! // 定义闭包,可选类型,避免强制解包 var onUpdate: ((YourDataModel) -> Void)? var onCancel: (() -> Void)? init(with item: YourDataModel) { self.currentItem = item super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func saveTapped() { onUpdate?(currentItem) // 调用闭包传数据 navigationController?.popViewController(animated: true) } @objc private func cancelTapped() { onCancel?() // 调用取消闭包 navigationController?.popViewController(animated: true) } }
在A页面创建B时设置闭包
注意要用[weak self]避免循环引用:
class ListViewController: UIViewController { // ... private func goToDetailPage() { let detailVC = DetailViewController(with: selectedItem) // 设置更新闭包 detailVC.onUpdate = { [weak self] updatedItem in guard let self = self else { return } self.updateList(with: updatedItem) } // 设置取消闭包 detailVC.onCancel = { print("用户取消了操作") } navigationController?.pushViewController(detailVC, animated: true) } }
总结一下
- 正向传数据:优先用自定义初始化传参,类型安全,逻辑清晰。
- 反向传数据:复杂交互用代理协议,简单场景用闭包,两者都是安全可控的,不会有单例的耦合问题。
- 单例尽量只用来存全局配置类的静态数据,别用来传业务数据。
内容的提问来源于stack exchange,提问作者Esclapyus
相关产品推荐
相关产品推荐

