如何在Swift中正确fire/call一个"selector"?

How to properly fire/call a "selector" in Swift?

问题总结:

如果您有一个 Swift class 将选择器作为其初始化器中的参数,您如何手动 "fire/call" 该选择器?

完整问题:

考虑以下在 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")
        }

    }


}

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

[父 Class]:

// { ...

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

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

我正在尝试实现同样的事情,据我所知,行:

perform(selector)

应该触发父级 class 中的选择器,但我却收到错误:"unrecognized selector sent to instance 0x600001740030"

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

我也尝试过对代码进行各种调整(更改 public/private、变量范围和 performSelector() 函数的不同形式)...但无法找到正确的方法让选择器触发...或者我犯的无关错误(如果有的话)。

感谢您的帮助。

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

上指定的选择器

通过调用 perform(selector) 就好像你在调用 self.perform(selector)(隐含了 self),通过这样做,ValueAnimator class 的当前实例是实际执行的对象选择器。发生这种情况时,它会尝试调用 ValueAnimator class 的一个名为 temp() 的方法,但由于它不存在,应用程序正在崩溃。

你可以验证如果你在ValueAnimator中添加一个temp()方法:

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

如果您 运行 现在不会崩溃,"Wrong Selector!!!" 消息将出现在控制台上。

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

在 ValueAnimator class 中声明如下 属性:

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() 方法。

希望对您有所帮助。