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

时间:2019-11-20 01:32:48

标签: ios swift timer callback selector

问题摘要:

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

完整问题:

请考虑以下在Swift中创建自定义计时器的尝试:

(-B + math.sqrt(B**2 - 4*A*C)) / 2 / A  

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

[在父班级]:

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")
        }

    }


}

我正在尝试实现同一件事,并且据我所知,这行代码:

// { ...

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

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

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

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

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

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

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

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

@objc func temp() {
    print("Wrong method!!!")
}

如果您现在运行,就不会崩溃,并且“选择器错误!!!”消息将出现在控制台上。

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

在ValueAnimator类中声明以下属性:

private var target: AnyObject

更新init方法,使其可以将目标作为参数:

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

    self.target = target
}

还更新timerCallback()

@objc func timerCallback() {
    ...

    _ = target.perform(selector)

    ...
}

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

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

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

希望对您有帮助。

答案 1 :(得分:1)

您在错误的对象上调用Perform:它是NSObject的实例方法,因此您尝试在perform上调用ValueAnimator,而ValueAnimator没有响应"temp"。您必须同时传入要执行的对象和选择器,然后使用选择器对该对象调用执行。请注意,这正是Timer的作用:您必须将self作为对象传递,并且计时器调用您在self上指定的选择器。