工具类中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的错误设置也可能埋下隐患。
修复方法分两种情况:
- 如果这个按钮需要点击事件:
修改工具方法,让调用方(比如你的视图控制器)传入负责处理点击的对象(target)和对应的方法选择器(action):
然后在你的视图控制器里调用时,传入当前控制器作为target: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 } }BarButton.items(navigationItem: self.navigationItem, target: self, action: #selector(leftLabelTapped)) // 别忘了实现点击方法,必须加@objc! @objc func leftLabelTapped() { // 这里写你的点击逻辑 } - 如果这个按钮不需要点击事件:
直接把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
相关产品推荐
相关产品推荐

