iOS导航栏按钮点击报错:Unrecognized selector sent to UITabBarController实例问题排查
这个问题我之前也碰到过,核心原因是你搞混了 selector 的 target 对象!
你的错误日志已经给出了关键线索:-[UITabBarController returnToGalleryScreenTab]: unrecognized selector sent to instance —— 系统尝试给 UITabBarController 发送 returnToGalleryScreenTab 这个消息,但它根本没有这个方法。
看你扩展里的这段代码:
button.addTarget(self, action: selector, for: .touchUpInside)
这里的 self 是调用该方法的 TabBarController 实例,而你的 returnToGalleryScreenTab 和 routeToAddPhotoForm 方法是定义在当前的 ViewController 里的。当按钮点击时,系统会按照你设置的 target(TabBarController)去查找对应的 selector,找不到自然就报错了。
两种可行的修复方案
方案1:给扩展方法添加 target 参数
修改 TabBarController 的扩展,让它同时接收 selector 和对应的 target 对象(也就是你的 ViewController),这样按钮的 target 就会指向正确的对象:
extension UITabBarController { func setLeftNavBarView(target: Any?, selector: Selector) { let button = UIButton(type: .custom) button.setTitle("Cancel", for: .normal) button.setTitleColor(UIColor(rgb: 0xFF5F5F5F), for: .normal) button.titleLabel?.font = UIFont(name: "Roboto", size: 15) // 这里把 target 换成传入的对象,而非 TabBarController 自身 button.addTarget(target, action: selector, for: .touchUpInside) button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) let barButton = UIBarButtonItem(customView: button) navigationItem.leftBarButtonItem = barButton } func setRightNavBarView(target: Any?, selector: Selector) { let button = UIButton(type: .custom) button.setTitle("Next", for: .normal) button.setTitleColor(UIColor(rgb: 0xFFCF497E), for: .normal) button.titleLabel?.font = UIFont(name: "Roboto-Bold", size: 15) // 同样替换 target button.addTarget(target, action: selector, for: .touchUpInside) button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) let barButton = UIBarButtonItem(customView: button) navigationItem.rightBarButtonItem = barButton } }
然后在你的 ViewController 里调用时,把当前 VC 作为 target 传进去:
override func viewDidLoad() { super.viewDidLoad() // ... 其他代码 self.tabBarController?.setLeftNavBarView(target: self, selector: #selector(self.returnToGalleryScreenTab)) self.tabBarController?.setRightNavBarView(target: self, selector: #selector(self.routeToAddPhotoForm)) }
方案2:直接在 ViewController 里设置导航栏按钮(更推荐)
其实导航栏的 navigationItem 是属于当前 ViewController 的属性,没必要绕到 TabBarController 里设置。你可以把按钮创建逻辑直接放到当前 VC 中,这样逻辑更直观,也彻底避免了 target 混淆的问题:
override func viewDidLoad() { super.viewDidLoad() // ... 其他代码 setupNavigationBarButtons() } private func setupNavigationBarButtons() { // 配置左侧 Cancel 按钮 let leftButton = UIButton(type: .custom) leftButton.setTitle("Cancel", for: .normal) leftButton.setTitleColor(UIColor(rgb: 0xFF5F5F5F), for: .normal) leftButton.titleLabel?.font = UIFont(name: "Roboto", size: 15) leftButton.addTarget(self, action: #selector(returnToGalleryScreenTab), for: .touchUpInside) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftButton) // 配置右侧 Next 按钮 let rightButton = UIButton(type: .custom) rightButton.setTitle("Next", for: .normal) rightButton.setTitleColor(UIColor(rgb: 0xFFCF497E), for: .normal) rightButton.titleLabel?.font = UIFont(name: "Roboto-Bold", size: 15) rightButton.addTarget(self, action: #selector(routeToAddPhotoForm), for: .touchUpInside) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightButton) } @objc func routeToAddPhotoForm() { self.presenter?.routeToAddPhotoForm() } @objc func returnToGalleryScreenTab() { self.tabBarController?.selectedIndex = 0 }
这种方式所有逻辑都集中在当前 VC,target 明确指向自身,不会再出现 selector 找不到的问题。
内容的提问来源于stack exchange,提问作者Ivanius

