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

如何在UITableView扩展中为UIButton添加Target事件?

在UITableView扩展中为按钮添加点击事件的解决方案

我懂你现在的困扰——想在UITableView的空状态扩展里给按钮加上点击事件,但直接用addTarget会发现找不到合适的响应对象对吧?毕竟扩展里的self是UITableView实例,它本身不应该处理业务逻辑的点击事件。这里有两种实用的方案,帮你搞定这个需求:


方案一:用闭包轻量传递点击逻辑

这种方法最简洁,适合简单的点击场景,直接把点击后的逻辑以闭包的形式传入扩展方法:

import UIKit

extension UITableView{
    func setEmptyView(title: String, message: String, buttonAction: @escaping () -> Void) {
        // 创建按钮
        let button = UIButton(type: .system)
        button.setTitle("+ Add New Documentation", for: .normal)
        button.titleLabel!.font = UIFont(name: "Roboto-Regular", size: 24)
        button.setTitleColor(UIColor(hex: "BDC86F"), for: .normal)
        button.backgroundColor = UIColor(hex: "506182")
        
        // 给按钮添加点击事件,用关联对象存储闭包
        button.addTarget(self, action: #selector(emptyButtonTapped(_:)), for: .touchUpInside)
        objc_setAssociatedObject(button, &AssociatedKeys.emptyButtonAction, buttonAction, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        
        // 补充emptyView创建、布局代码(示例)
        let emptyView = UIView(frame: self.bounds)
        button.translatesAutoresizingMaskIntoConstraints = false
        emptyView.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: emptyView.centerXAnchor),
            button.topAnchor.constraint(equalTo: emptyView.centerYAnchor, constant: 20)
        ])
        
        self.backgroundView = emptyView
    }
    
    // 私有方法中转点击事件,调用闭包
    @objc private func emptyButtonTapped(_ sender: UIButton) {
        if let action = objc_getAssociatedObject(sender, &AssociatedKeys.emptyButtonAction) as? () -> Void {
            action()
        }
    }
}

// 定义关联对象的Key(避免命名冲突)
private enum AssociatedKeys {
    static var emptyButtonAction = "emptyButtonAction"
}

使用方式(在你的ViewController里):

// 当需要显示空视图时调用
tableView.setEmptyView(title: "暂无文档", message: "点击添加新文档") {
    print("Hello World!")
    // 这里写你的点击逻辑,比如跳转到添加文档页面
}

方案二:用代理模式处理复杂交互

如果你的空视图按钮需要更复杂的交互逻辑,或者要在多个ViewController里复用,代理模式会更合适:

第一步:定义代理协议

protocol TableViewEmptyViewDelegate: AnyObject {
    func emptyViewAddButtonTapped()
}

第二步:修改UITableView扩展

import UIKit

extension UITableView{
    // 用关联对象添加代理属性(扩展不能直接添加存储属性)
    weak var emptyViewDelegate: TableViewEmptyViewDelegate? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.emptyViewDelegate) as? TableViewEmptyViewDelegate
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.emptyViewDelegate, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
    
    func setEmptyView(title: String, message: String) {
        let button = UIButton(type: .system)
        button.setTitle("+ Add New Documentation", for: .normal)
        button.titleLabel!.font = UIFont(name: "Roboto-Regular", size: 24)
        button.setTitleColor(UIColor(hex: "BDC86F"), for: .normal)
        button.backgroundColor = UIColor(hex: "506182")
        
        button.addTarget(self, action: #selector(emptyButtonTapped(_:)), for: .touchUpInside)
        
        // 补充emptyView的创建和布局代码(示例)
        let emptyView = UIView(frame: self.bounds)
        button.translatesAutoresizingMaskIntoConstraints = false
        emptyView.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: emptyView.centerXAnchor),
            button.topAnchor.constraint(equalTo: emptyView.centerYAnchor, constant: 20)
        ])
        
        self.backgroundView = emptyView
    }
    
    @objc private func emptyButtonTapped(_ sender: UIButton) {
        // 通知代理处理点击事件
        emptyViewDelegate?.emptyViewAddButtonTapped()
    }
}

private enum AssociatedKeys {
    static var emptyViewDelegate = "emptyViewDelegate"
}

使用方式(在你的ViewController里):

class YourViewController: UIViewController, TableViewEmptyViewDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.emptyViewDelegate = self
        // 显示空视图
        tableView.setEmptyView(title: "暂无文档", message: "点击添加新文档")
    }
    
    // 实现代理方法
    func emptyViewAddButtonTapped() {
        print("Hello World!")
        // 处理按钮点击逻辑
    }
}

简单说下为什么不能直接用self作为target:UITableView是UI组件,不该承担业务逻辑的处理,点击事件应该由持有它的ViewController来负责,所以我们通过闭包或代理把逻辑传递进去,这样既保持了扩展的复用性,又让业务逻辑归属更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:52:47