Swift3中Selector引起的unrecognized selector sent to instance

状况

OC项目转Swift,学习Swift中,不断挖坑填坑。这次遇到了一个常见的Crash unrecognized selector sent to instance。代码如下:

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.button.addTarget(self, action: Selector("onButtonClicked:"), for: .touchUpInside)
    }
    
    func onButtonClicked(sender: UIButton) {
        sender.superview!.animateWhenClicked()
    }

原因

编译的时候并没有错误,但是有个警告报出。No method declared with Objective-C selector 'onButtonClicked:'

深究一下,Selector 源自Objective-C中的 SEL 类型。在Swift中,Selector是结构体,可以使用字符串来构造。

self.button.addTarget(self, action: Selector("onButtonClicked:"), for: .touchUpInside)

但若传入的字符串没有对应的方法名,那么程序在执行时就会Crash unrecognized selector sent to instance。本人遇到的问题也正是如此。

解决方法

修改一下函数的参数名定义,函数可以同时拥有外部参数和内部参数,名字可以不同。可以使用下划线来省略外部参数名。

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.button.addTarget(self, action: Selector("onButtonClicked:"), for: .touchUpInside)
    }
    
    func onButtonClicked(_ sender: UIButton) {
        sender.superview!.animateWhenClicked()
    }

再次编译运行,成功调用到此函数。但此时,编译的时候会报出一个新的警告Use '#selector' instead of explicitly constructing a 'Selector'#selector()的好处是不再需要使用字符串来构造,也是Swift3中的方式。再修改一下代码。

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.button.addTarget(self, action: #selector(onButtonClicked(_:)), for: .touchUpInside)
    }
    
    func onButtonClicked(_ sender: UIButton) {
        sender.superview!.animateWhenClicked()
    }

注意:如果函数名不唯一的话,#selector中调用函数时要加上作用域

self.button.addTarget(self, action: #selector(ViewController.onButtonClicked(_:)), for: .touchUpInside)

另外这样写也没问题

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.button.addTarget(self, action: #selector(onButtonClicked(sender:)), for: .touchUpInside)
    }
    
    func onButtonClicked(sender: UIButton) {
        sender.superview!.animateWhenClicked()
    }

参考资料

  1. Swift 中的 Selector
  2. Swift 函数

你可能感兴趣的:(Swift3中Selector引起的unrecognized selector sent to instance)