接收方ViewController未加载时,仅能靠单例或静态属性传值吗?
问题分析
你当前的传值问题核心在于静态代理的时机错误:
- 创建
ProductDetailViewController实例后立刻调用ProductViewController.delegate?.didReceiveData,但此时nextVC的viewDidLoad尚未执行(该方法在VC被推入导航栈后才会触发),静态delegate仍为nil,导致传值失败。 - 仅当详情VC被加载过一次后,静态
delegate被赋值为已存在的实例,后续调用才能生效,但这种用法违背代理模式设计初衷,还会带来内存泄漏风险。
正确解决方案
对于列表→详情的正向页面跳转场景,直接给目标VC的属性赋值是最简单、安全的方案,完全不需要代理模式(代理更多用于反向传值,比如详情页通知列表页更新数据)。
修改后的代码
数据发送方 ProductViewController
import UIKit final class ProductViewController: UIViewController { // 移除不必要的静态代理属性 private let productTableView = UITableView() let productList : [Product] = [ Product(name: "1907 Wall Set", cellImageName: "image-cell1", fullscreenImageName: "phone-fullscreen1"), Product(name: "1921 Dial Phone", cellImageName: "image-cell2", fullscreenImageName: "phone-fullscreen2"), Product(name: "1937 Desk Set", cellImageName: "image-cell3", fullscreenImageName: "phone-fullscreen3"), Product(name: "1984 Moto Portable", cellImageName: "image-cell4", fullscreenImageName: "phone-fullscreen4") ] override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemGray6 setTable() setUI() } func setTable() { productTableView.delegate = self productTableView.dataSource = self productTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "Reused") productTableView.rowHeight = 94 productTableView.backgroundColor = .systemGray6 let header = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 18)) productTableView.tableHeaderView = header } func setUI() { productTableView.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(productTableView) NSLayoutConstraint.activate([ productTableView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor), productTableView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor), productTableView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), productTableView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor) ]) } } extension ProductViewController : UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return productList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Reused", for: indexPath) as! CustomTableViewCell cell.productName.text = productList[indexPath.row].name ?? "nonamed" cell.productImage.image = UIImage(named: productList[indexPath.row].cellImageName ?? "star") return cell } } extension ProductViewController : UITableViewDelegate{ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let nextVC = ProductDetailViewController() // 直接给目标VC的属性赋值完成传值 nextVC.currentProduct = productList[indexPath.row] self.navigationController?.pushViewController(nextVC, animated: true) } }
数据接收方 ProductDetailViewController
import UIKit // 移除不需要的代理协议 final class ProductDetailViewController: UIViewController { var currentProduct : Product? override func viewDidLoad() { super.viewDidLoad() // 移除静态代理赋值代码 // 这里可直接使用currentProduct进行UI渲染,示例: if let product = currentProduct { title = product.name // 其他UI初始化操作... } } }
为什么不推荐用代理做正向传值?
- 代理模式的核心是反向回调,正向传值用代理属于过度设计,会增加不必要的复杂度。
- 静态
delegate会持有VC实例,导致内存无法正常释放,多VC实例场景下还会出现代理混乱的问题。
内容的提问来源于stack exchange,提问作者Hide_In_Swift
相关产品推荐
相关产品推荐

