协议扩展和addTarget与NSInvalidArgumentException崩溃

时间:2016-02-09 12:20:38

标签: ios swift

协议扩展和addTarget崩溃并显示消息:由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [Test.UIButton touchDown:]:无法识别的选择器发送到实例0x157eee8e0'

touchDown函数无法识别的问题在哪里?

protocol MyButtonProtocol {
    var holdTimer: NSTimer? { get set }
}
extension MyButtonProtocol where Self: UIButton {
    func enable() {
        addTarget(self, action: "touchDown:", forControlEvents: UIControlEvents.TouchDown)
    }
    mutating func touchDown(sender: UIButton) {
        print("Touch down!")
        holdTimer = NSTimer(timeInterval: 1, target: self, selector: Selector("didTimeOut"), userInfo: nil, repeats: true)
    }
}
// Usage:
let button = UIButton()
button.enable()

3 个答案:

答案 0 :(得分:1)

这都很奇怪。

您的代码

let button = UIButton()
button.enable()

似乎不完整,因为实例button未采用协议MyButtonProtocol

如果我写

class MyButton: UIButton, MyButtonProtocol {
    var holdTimer: NSTimer?
    func touch3(sender: AnyObject?) {
        print("touch3 \(sender)")
    }
}

然后

let myButton = MyButton()
myButton.enable() // this works ok
print("touch3: \(myButton.respondsToSelector(Selector("touch3:")))")
print("touchDown: \(myButton.respondsToSelector(Selector("touchDown:")))")
print("enable \(myButton.respondsToSelector(Selector("enable")))")

然后我看到输出

touch3: true
touchDown: false
enable false

所以程序成功调用了enable()方法,但respondsToSelector似乎没有检查协议扩展中的方法。 enable正在运行,因为如果我将呼叫更改为

addTarget(self, action: "touch3:", forControlEvents: UIControlEvents.TouchDown)

然后成功到达touch3

这是NSObject.respondsToSelector

的实施中的错误吗?

几周前我注意到我无法使用协议扩展中的函数覆盖super中的函数。我认为这只是我误解的一种语言特征。也许这是同一问题的另一个症状?

答案 1 :(得分:0)

protocol MyButtonProtocol {
    var holdTimer: NSTimer? { get set }
}
extension MyButtonProtocol where Self: UIButton {
    var holdTimer: NSTimer? {
        get {
            return holdTimer
        }
        set {
            holdTimer = newValue;
        }
    }

    func enable() {
        addTarget(self, action: "touchDown:", forControlEvents: UIControlEvents.TouchDown)
    }
    mutating func touchDown(sender: UIButton) {
        print("Touch down!")
        holdTimer = NSTimer(timeInterval: 1, target: self, selector: Selector("didTimeOut"), userInfo: nil, repeats: true)
    }
}

extension UIButton: MyButtonProtocol {
}

// Usage:
let button = UIButton()
button.enable()

注意为UIButton编写的扩展,这是必需的,因为你编写了一个协议,但是UIButton需要实现它才能使它生效。我还在协议扩展中为holdTimer编写了getter和setter。您也可以在UIButton扩展名中写下此内容。

答案 2 :(得分:0)

来自Apple Bug报告小组的回答:

  

Engineering已确定此问题的行为符合预期   关于以下信息:Swift协议扩展不是   可用于Objective-C。只能使用类的扩展   目标C