如何在 Swift 中正确触发/调用“选择器”?

Boo*_*unz 3 timer callback selector ios swift

问题摘要:

如果您有一个 Swift 类,该类在其初始化程序中将选择器作为参数,那么如何手动“触发/调用”该选择器?

完整问题:

考虑以下在 Swift 中制作自定义计时器的尝试:

let TIME_INTERVAL = 0.1

class ValueAnimator : NSObject {
    private var timer = Timer()

    private let maxRep: Int
    private var currentRepIndex: Int = 0

    private var selector: Selector

    init(durationInSeconds: Int, selector: Selector) {
        print("VALUEANIMATOR INIT")
        self.maxRep = Int(Double(durationInSeconds) / TIME_INTERVAL)
        self.selector = selector

    }

    func start() {
        timer = Timer.scheduledTimer(timeInterval: TIME_INTERVAL, target: self, selector: (#selector(timerCallback)), userInfo: nil, repeats: true)
    }

    @objc func timerCallback() {
        currentRepIndex += 1

        perform(selector) // <-------- this line causes crash, "unrecognized selector sent to instance 0x600001740030"

        print ("VA timer called!, rep: \(currentRepIndex)")
        if currentRepIndex == maxRep {
            timer.invalidate()
            print("VA timer invalidated")
        }

    }


}
Run Code Online (Sandbox Code Playgroud)

这个“ValueAnimator”的用法与普通的 Timer/NSTimer 类似,因为您传递一个“选择器”作为参数,并且每次 ValueAnimator 触发时都会调用该选择器:

【家长课堂】:

// { ...

   let valueAnimatorTest = ValueAnimator(durationInSeconds: 10, selector: #selector(self.temp))
        valueAnimatorTest.start()
    }

    @objc func temp() {
        print("temp VA callback works!") // this doesn't happen :(
    }
Run Code Online (Sandbox Code Playgroud)

我正在尝试实现同样的事情,据我了解,该行:

perform(selector)
Run Code Online (Sandbox Code Playgroud)

应该触发父类中的选择器,但我收到错误:“无法识别的选择器发送到实例 0x600001740030”

我有点不知所措。我尝试过谷歌搜索错误,但每个人似乎都在谈论如何使用父端的选择器(如何使用 Timer.scheduledTimer() 等),但我已经知道如何成功做到这一点。

我还尝试了对代码的各种调整(更改公共/私有、变量范围以及不同形式的 PerformSelector() 函数)...但无法找出使选择器触发的正确方法...或者我犯过的不相关的错误(如果有的话)。

谢谢你的帮助。

Gab*_*abb 6

通过调用perform(selector)它就像您在调用一样self.perform(selector)(隐含 self),并且通过这样做,ValueAnimator 类的当前实例是实际执行选择器的对象。发生这种情况时,它会尝试调用 ValueAnimator 类的方法temp(),但由于该方法不存在,因此应用程序崩溃。

您可以验证是否temp()在 ValueAnimator 中添加方法:

@objc func temp() {
    print("Wrong method!!!")
}
Run Code Online (Sandbox Code Playgroud)

如果你现在运行,你将不会出现崩溃和“错误的选择器!!!”的情况。消息将出现在控制台上。

问题的解决方案是将应该运行选择器方法的对象与选择器一起传递给 ValueAnimator 对象的初始化。

在 ValueAnimator 类中声明以下属性:

private var target: AnyObject
Run Code Online (Sandbox Code Playgroud)

更新该init方法,以便它可以获取目标作为参数:

init(durationInSeconds: Int, selector: Selector, target: AnyObject) {
    ...

    self.target = target
}
Run Code Online (Sandbox Code Playgroud)

还更新timerCallback()

@objc func timerCallback() {
    ...

    _ = target.perform(selector)

    ...
}
Run Code Online (Sandbox Code Playgroud)

最后,当您初始化 ValueAnimator 实例时,也传递选择器所属的对象:

let valueAnimatorTest = ValueAnimator(durationInSeconds: 10, selector: #selector(self.temp), target: self)
Run Code Online (Sandbox Code Playgroud)

再次运行,temp()这次将执行正确的方法。

我希望它有帮助。