【问题标题】:Swift NSTimer unrecognized selector sent to instance timerFireMethodSwift NSTimer 无法识别的选择器发送到实例 timerFireMethod
【发布时间】:2016-01-30 14:15:27
【问题描述】:

我正在用 Swift 为 iOS 9.2 编写一些计时器代码 我通过 xcode 下载了最新的 iOS 9.2 文档 他们显示

(void)timerFireMethod:(NSTimer *)timer

但这行不通。 如果我使用这样的签名

func timerFire(timer : NSTimer?)
func timerFire(timer : NSTimer)

然后我得到错误

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[DSP1.PlayManager timerFire]: unrecognized selector sent to instance

我唯一能开始工作的就是这样的呼叫签名

func play(sound : String)
{
    bsound = theLM?.getPlayer(sound)
    bsound?.delegate = self
    bsound?.play()
    stimer = NSTimer(timeInterval: 1.0, target: self, selector: Selector("timerFire"), userInfo: self, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(stimer!, forMode: NSDefaultRunLoopMode)
}

// Docs say signature should be (void)timerFireMethod:(NSTimer *)timer.      Docs are wrong
func timerFire()
{
    print("Player at: \(bsound?.currentTime) out of \(bsound?.duration) seconds");
}

但这与通过 XCode 下载的最新 iOS 9.2 文档所说的不匹配。

  • 我这样做对吗?
  • 为什么新加载的 iOS 9.2 文档似乎有错误的签名?
  • 其他人在阅读哪些有关 Swift iOS 编程的准确文档?

(编辑更清楚的是文档中列出的回调签名在运行时无法工作)

答案:

在对 NSTimer 的调用中,如果作为 Selector 传入的函数名称有一个尾随冒号,则表示您希望将计时器作为参数传递给您的方法。没有冒号意味着您不希望将计时器作为参数传递。

NSTimer(timeInterval: 1.0, target: self, selector: Selector("timerFire"), userInfo: self, repeats: true)
func timerFire()

NSTimer(timeInterval: 1.0, target: self, selector: Selector("timerFire:"), userInfo: self, repeats: true)
func timerFire(timer : NSTimer)

NSTimer 的文档在选择器参数中提到了这一点,但还不清楚。 "选择器应具有以下签名:timerFireMethod:(包括一个冒号,表示该方法接受一个参数)。"

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    你犯了一个简单但常见的错误。

    你的方法签名应该是:

    func timerFire(timer: NSTimer) {}
    

    你的定时器设置应该是:

    NSTimer(timeInterval: 1.0, target: self, selector: "timerFire:", userInfo: nil, repeats: true)
    

    错误是您在选择器名称中缺少冒号。 timerFiretimerFire: 不同。跳过冒号,它会寻找这样的方法:

    func timerFire() {}
    

    没有 NSTimer 参数。最好包含参数,因此包含冒号,这样您就可以确认您获得的计时器是您期望的。

    通知也是如此。如果您使用的是通知中心,请在方法中包含冒号和通知对象。

    【讨论】:

    • 优秀。确认选择器上的尾随冒号与参数版本 timerFire(timer: NSTimer) 匹配,并且选择器上的尾随冒号与无参数 timerFire() 匹配。 ---- 结果 NSTimer 的文档页面确实有一个关于 scheduleTimerWithTimeInterval 的选择器参数的注释,上面写着“选择器应该具有以下签名:timerFireMethod:(包括一个冒号,表示该方法需要一个参数)”但它是远未清楚。
    【解决方案2】:

    您的代码似乎没问题。您的计时器的选择器没有预定义的签名,只要您的类中有一个具有该名称的方法,您就可以随意使用它。

    func play(sound : String) {
        // ....
        stimer = NSTimer(timeInterval: 1.0, target: self, selector: "methodToRunOnTimerTick", userInfo: self, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(stimer!, forMode: NSDefaultRunLoopMode)
    }
    
    func methodToRunOnTimerTick() {
        print("Player at: \(bsound?.currentTime) out of \(bsound?.duration) seconds");
    }
    

    要记住的另一件事是,您决定使用的方法也可以在调用计时器时将其作为参数接收。这个案例看起来像这样:

    func play(sound : String) {
        // ....
        stimer = NSTimer(timeInterval: 1.0, target: self, selector: "methodToRunOnTimerTick:", userInfo: self, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(stimer!, forMode: NSDefaultRunLoopMode)
    }
    
    func methodToRunOnTimerTick(timer: NSTimer) {
        print("Player at: \(bsound?.currentTime) out of \(bsound?.duration) seconds");
    }
    

    所以你以正确的方式实现计时器,该方法不需要特殊的签名。如果您需要更多帮助,请告诉我。祝你的项目好运!

    【讨论】:

    • 这对我不起作用。当我将签名更改为文档所说的应该工作时,`func timerFire(timer : NSTimer?)' 然后我收到错误 *** Terminating app due to unaught exception 'NSInvalidArgumentException', reason: '-[DSP1.PlayManager timerFire ]: 无法识别的选择器发送到实例,
    • 那是因为你的代码中没有func timerFire(timer : NSTimer?)方法,所以当它试图调用选择器时,它不存在。
    • 现在我明白了,NSTimer 初始化调用中的尾随冒号太微妙了,我需要指出它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    相关资源
    最近更新 更多