You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

接收方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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:32:40