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

Swift UI Delegate方法优化:解决多UIViewController中UITableView代理代码重复问题

优化方案

你可以通过「抽离独立的代理数据源对象」的组合模式来消除重复代码,相比继承基类的方案灵活度更高,后续自定义扩展也更方便,具体实现步骤如下:

步骤1:定义通用的TableView代理处理类

首先创建一个泛型的代理类,兼容不同的Model和Cell类型:

import UIKit

class TableViewDataSourceDelegate<T, Cell: UITableViewCell>: NSObject, UITableViewDataSource, UITableViewDelegate {
    // 存储数据源
    var items: [T] = []
    // Cell复用ID
    private let cellIdentifier: String
    // Cell配置回调
    private let configureCell: (Cell, T, IndexPath) -> Void
    // 点击Cell回调
    private let didSelectItem: (T, IndexPath) -> Void
    
    // 初始化方法
    init(cellIdentifier: String, 
         configureCell: @escaping (Cell, T, IndexPath) -> Void,
         didSelectItem: @escaping (T, IndexPath) -> Void) {
        self.cellIdentifier = cellIdentifier
        self.configureCell = configureCell
        self.didSelectItem = didSelectItem
        super.init()
    }
    
    // MARK: - UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? Cell else {
            return UITableViewCell()
        }
        let item = items[indexPath.row]
        configureCell(cell, item, indexPath)
        return cell
    }
    
    // MARK: - UITableViewDelegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let item = items[indexPath.row]
        didSelectItem(item, indexPath)
    }
}

步骤2:在ViewController中使用

改造后的ViewController代码会大幅精简,不需要再实现重复的代理方法:

class FirstViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    var userArray = [UserModel]()
    // 声明代理数据源对象
    private var tableViewHandler: TableViewDataSourceDelegate<UserModel, UserTableViewCell>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册Cell
        tableView.register(UserTableViewCell.self, forCellReuseIdentifier: "Cell01")
        // 初始化代理对象,传入配置和点击回调
        tableViewHandler = TableViewDataSourceDelegate(
            cellIdentifier: "Cell01",
            configureCell: { cell, user, indexPath in
                // 在这里配置Cell内容
                cell.nameLabel.text = user.name
                cell.avatarImageView.image = UIImage(named: user.avatar)
            },
            didSelectItem: { [weak self] user, indexPath in
                // 在这里处理点击逻辑
                self?.navigateToUserDetail(user: user)
            }
        )
        // 把tableView的代理和数据源绑定到自定义的handler上
        tableView.delegate = tableViewHandler
        tableView.dataSource = tableViewHandler
    }
    
    // 获取到数据后刷新列表
    func reloadUserData(_ users: [UserModel]) {
        tableViewHandler.items = users
        tableView.reloadData()
    }
    
    private func navigateToUserDetail(user: UserModel) {
        // 跳转逻辑
    }
}

// 第二个商品列表控制器同理,只需要替换泛型类型即可
class SecondViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    var productArray = [ProductModel]()
    private var tableViewHandler: TableViewDataSourceDelegate<ProductModel, ProductTableViewCell>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(ProductTableViewCell.self, forCellReuseIdentifier: "Cell01")
        tableViewHandler = TableViewDataSourceDelegate(
            cellIdentifier: "Cell01",
            configureCell: { cell, product, indexPath in
                cell.titleLabel.text = product.title
                cell.priceLabel.text = "¥\(product.price)"
            },
            didSelectItem: { [weak self] product, indexPath in
                self?.navigateToProductDetail(product: product)
            }
        )
        tableView.delegate = tableViewHandler
        tableView.dataSource = tableViewHandler
    }
}

扩展说明

  • 如果需要实现更多代理方法(比如自定义行高、区头区尾),只需要在TableViewDataSourceDelegate类中补充对应的实现即可,所有用到的控制器都能复用
  • 如果个别控制器需要特殊的代理逻辑,不需要修改通用类,单独给当前控制器实现对应的代理方法即可,不会影响其他页面
  • 这种组合方式也支持同一个控制器内多个TableView的场景,只需要创建多个对应的handler对象分别绑定即可

内容的提问来源于stack exchange,提问作者Muhammad Haroon Iqbal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 09:24:03