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

UIViewController与UITableViewDelegate间通信的最优实现方案咨询

最优实现方案分析

这是iOS开发中很常见的组件解耦场景,直接给数据源类加VC的弱引用虽然能解决问题,但并不是最优解——我们有更优雅、低耦合的方式来处理这个需求,下面给你梳理几个常用方案:

方案一:闭包回调(推荐,轻量场景首选)

这种方式最简洁,而且能完美避免循环引用问题。你可以在你的UITableViewDataSource(兼Delegate)类里定义一个闭包属性,用来传递选中事件:

class CustomDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
    // 定义回调闭包,参数可以根据需求调整(比如传模型、indexPath等)
    var didSelectRow: ((IndexPath) -> Void)?
    
    // 实现didSelectRowAtIndexPath
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 触发闭包
        didSelectRow?(indexPath)
    }
    
    // 其他数据源方法...
}

然后在你的UIViewController里,初始化数据源的时候给这个闭包赋值,注意用[weak self]避免循环引用:

class YourViewController: UIViewController {
    var tableView: UITableView!
    var dataSource1: CustomDataSource!
    var dataSource2: CustomDataSource!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化数据源1
        dataSource1 = CustomDataSource()
        dataSource1.didSelectRow = { [weak self] indexPath in
            guard let self = self else { return }
            // 在这里执行segue或者弹窗
            self.performSegue(withIdentifier: "YourSegueID", sender: indexPath)
            // 或者显示弹窗
            let alert = UIAlertController(title: "提示", message: "选中了第\(indexPath.row)行", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            self.present(alert, animated: true)
        }
        
        // 数据源2同理...
        dataSource2 = CustomDataSource()
        dataSource2.didSelectRow = { [weak self] indexPath in
            // 处理另一种数据源的选中逻辑
        }
    }
    
    // 根据条件切换数据源
    func switchDataSource(_ condition: Bool) {
        tableView.dataSource = condition ? dataSource1 : dataSource2
        tableView.delegate = condition ? dataSource1 : dataSource2
        tableView.reloadData()
    }
}

方案二:自定义代理协议(适合多回调场景)

如果你的数据源需要传递多种事件(不止选中),自定义代理会更规范,可读性更强。

首先定义一个代理协议:

protocol DataSourceSelectionDelegate: AnyObject {
    func dataSource(_ dataSource: CustomDataSource, didSelectRowAt indexPath: IndexPath)
    // 可以添加更多回调方法,比如didDeselectRow、didScroll等
}

然后在数据源类里添加弱引用的代理属性:

class CustomDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
    weak var delegate: DataSourceSelectionDelegate?
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        delegate?.dataSource(self, didSelectRowAt: indexPath)
    }
    
    // 其他数据源方法...
}

让你的UIViewController遵守这个协议并实现方法:

class YourViewController: UIViewController, DataSourceSelectionDelegate {
    var tableView: UITableView!
    var dataSource1: CustomDataSource!
    var dataSource2: CustomDataSource!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dataSource1 = CustomDataSource()
        dataSource1.delegate = self
        
        dataSource2 = CustomDataSource()
        dataSource2.delegate = self
    }
    
    // 实现代理方法
    func dataSource(_ dataSource: CustomDataSource, didSelectRowAt indexPath: IndexPath) {
        // 可以区分是哪个数据源触发的事件
        if dataSource === dataSource1 {
            // 处理数据源1的选中逻辑
            performSegue(withIdentifier: "SegueFromSource1", sender: indexPath)
        } else if dataSource === dataSource2 {
            // 处理数据源2的选中逻辑
            let alert = UIAlertController(title: "来自数据源2", message: "选中行:\(indexPath.row)", preferredStyle: .alert)
            present(alert, animated: true)
        }
    }
    
    // 切换数据源逻辑...
}

不推荐的方案:直接弱引用UIViewController

虽然给数据源类加weak var viewController: YourViewController?也能实现需求,但这种方式会让数据源和VC的耦合度变高——数据源不应该知道VC的存在,它只需要负责提供数据和传递事件即可。一旦VC的结构变化,数据源也需要修改,维护成本更高。

总结

  • 轻量场景(只有选中回调)优先用闭包,代码简洁、解耦性好;
  • 多回调场景优先用自定义代理,结构清晰、扩展性强;
  • 无论用哪种方式,都要注意使用弱引用(闭包用[weak self],代理属性加weak),避免循环引用导致内存泄漏。

内容的提问来源于stack exchange,提问作者ed'

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:52:43