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

工具类中Selector使用与定义问题及按钮点击崩溃排查求助

解决你的两个iOS开发问题:按钮点击崩溃 & 工具类中Selector的正确使用

一、先搞定按钮点击崩溃的问题

从你提供的代码片段来看,崩溃的核心原因是在静态方法里错误地把target设成了self:

let leftLabel = UIBarButtonItem(title: "", style: .plain, target: self, action: nil)

在static func items(...)这个静态方法里,self指的是BarButton这个类本身,而不是某个实例对象。如果后续你给这个按钮加上了点击事件(action),系统会尝试在BarButton类里找对应的方法,但你的工具类显然不会实现按钮的点击逻辑,这就直接导致找不到方法而崩溃——哪怕你现在action设的是nil,这种target的错误设置也可能埋下隐患。

修复方法分两种情况:

  1. 如果这个按钮需要点击事件:
    修改工具方法,让调用方(比如你的视图控制器)传入负责处理点击的对象(target)和对应的方法选择器(action):
    class BarButton{
        static func items(navigationItem: UINavigationItem, target: Any?, action: Selector?) {
            // 隐藏返回按钮
            navigationItem.hidesBackButton = true
            // 创建左侧按钮
            let leftLabel = UIBarButtonItem(title: "", style: .plain, target: target, action: action)
            leftLabel.tintColor = UIColor(red: 30/255, green: 104/255, blue: 168/255, alpha: 1)
            navigationItem.leftBarButtonItem = leftLabel
        }
    }
    
    然后在你的视图控制器里调用时,传入当前控制器作为target:
    BarButton.items(navigationItem: self.navigationItem, target: self, action: #selector(leftLabelTapped))
    
    // 别忘了实现点击方法,必须加@objc!
    @objc func leftLabelTapped() {
        // 这里写你的点击逻辑
    }
    
  2. 如果这个按钮不需要点击事件:
    直接把target和action都设为nil就行,避免系统瞎找方法:
    let leftLabel = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    

二、工具类中使用Selector的正确姿势

工具类的职责是封装通用创建逻辑,而不是处理业务逻辑(比如按钮点击),所以用Selector的时候,核心是让真正负责处理点击的对象(比如视图控制器)来提供target和对应的方法,工具类只负责把这两个参数传递给按钮。

额外推荐:用闭包替代Selector(更Swift的写法)

如果你觉得Selector用起来麻烦,还可以用闭包来处理点击,这样更符合Swift的语法风格,也不用写@objc方法:

class BarButton{
    static func items(navigationItem: UINavigationItem, onTap: (() -> Void)?) {
        navigationItem.hidesBackButton = true
        // 先创建一个自定义View来承载按钮,方便加手势
        let customView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 44))
        let leftLabel = UILabel()
        leftLabel.text = ""
        leftLabel.textColor = UIColor(red: 30/255, green: 104/255, blue: 168/255, alpha: 1)
        leftLabel.isUserInteractionEnabled = true
        customView.addSubview(leftLabel)
        leftLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            leftLabel.centerXAnchor.constraint(equalTo: customView.centerXAnchor),
            leftLabel.centerYAnchor.constraint(equalTo: customView.centerYAnchor)
        ])
        
        // 加点击手势
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        // 把闭包存在手势的userInfo里
        tapGesture.setValue(onTap, forKey: "tapHandler")
        leftLabel.addGestureRecognizer(tapGesture)
        
        let leftBarButton = UIBarButtonItem(customView: customView)
        navigationItem.leftBarButtonItem = leftBarButton
    }
    
    @objc private static func handleTap(_ gesture: UITapGestureRecognizer) {
        guard let tapHandler = gesture.value(forKey: "tapHandler") as? (() -> Void) else { return }
        tapHandler()
    }
}

调用的时候直接传闭包就行,非常清爽:

BarButton.items(navigationItem: self.navigationItem) {
    // 这里写点击后的逻辑
    print("左侧按钮被点击啦")
}

最后总结一下

  • 按钮崩溃的本质是target和action不匹配:要么target找不到对应的方法,要么target的类型不对(比如用了类而不是实例)。
  • 工具类里用Selector,一定要让调用方提供处理点击的target和方法;如果想更Swift,闭包是更好的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:01:54