将 NSTimer 目标消息发送到不同的 class;提取其 userInfo 参数

Sending an NSTimer target message to a different class; extracting its userInfo parameter

我正在使用 NSTimer 定期发送消息。这是代码:

{
    // ....
    var params : [String] = []
    params.append(conversion)
    params.append(message)
    let timer = NSTimer(fireDate: date, interval: 60, target: self, selector: Selector("importTextMessage.sendMessage:"), userInfo: params, repeats: true)

    NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    // ...
}


func sendMessage(params: [String]){ ...}

我也尝试过更改为 Swift 2.2 语法:

let timer = NSTimer(fireDate: date, interval: 60, target: self, selector: #selector(importTextMessage.sendMessage(_:)), userInfo: params, repeats: true)

但这并没有改变任何东西。

从发布的关于 "Unrecognized selector sent to instance" 的所有其他问题中,得到的答复是 "include a colon in the Selector so that it knows to grab arguments from UserInfo",但我已将其包括在内,但无法找出问题所在。

注意事项:

函数的参数和通过 NSTimer userInfo 传入的参数匹配。它们都是字符串数组。

如果这意味着什么,则代码在调用 sendMessage 时失败。它实际上并没有发送到 sendMessage。

我收到一个奇怪的警告说 "String literal is not a valid objective-c selector"

我尝试更改我的 sendMessage 代码,按照 1 位用户的建议将 Timer 作为参数:func sendMessage(timer: NSTimer){但仍然出现相同的错误。

提前感谢您的帮助,非常感谢。

编辑:这里是运行定时器的函数://保存所有数据 @IBAction func saveText(sender: AnyObject) { var phone : 双 活动变量:整数 可变频率:双 变种消息:字符串 变量日期:NSDate

    phone = Double(currentNumber)!
    active = 1
    message = myTextView.text
    date = myDatePicker.date

    switch self.frequency.selectedRowInComponent(0) {
        case 0:
            frequency = 1
        case 1:
            frequency = 3
        case 2:
            frequency = 6
        case 3:
            frequency = 24
        case 4:
            frequency = 168
        case 5:
            frequency = 744
        default:
            frequency = 8760
    }

    importTextMessage.seedMessage(phone, active: active, frequency: frequency, message: message, date: date)

    print(date)
    let conversion : String = "+1" + String(Int(phone))


    //importTextMessage.sendMessage("Ryan", to: conversion, message: message)
    var params : [String] = []
    params.append(conversion)
    params.append(message)
    //importTextMessage.sendMessage(params)

    let timer = NSTimer(fireDate: date, interval: 60, target: self, selector: #selector(importTextMessage.sendMessage(_:)), userInfo: params, repeats: true)
    //        
    NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)

}

编辑:确切错误消息:

无法识别的选择器发送到实例 0x7ffe6b915460 2016-07-25 13:26:09.092 骚扰你的凯特 [53524:9000621] *** 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序,原因:'-[Harass_Your_Kate.AddMessageViewController sendMessage:]: 无法识别选择器发送到实例 0x7ffe6b915460

来自doc

The timer passes itself as the argument

因此您的计时器需要其他参数类型,NSTimer。试试这个代码:

override func viewDidLoad() {        
    super.viewDidLoad()

    var params : [String] = []
    params.append(conversion)
    params.append(message)
    let timer = NSTimer(fireDate: date, interval: 60, target: self, selector: #selector(sendMessage(_:)), userInfo: params, repeats: true)
    NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
}

func sendMessage(sender: NSTimer) {
    print(sender.userInfo as? [String])
}

此代码在我的标准视图控制器中运行良好

NSTimer 的 API 是这样的,接收器(目标函数)必须接受一个且只有一个 NSTImer 类型的参数。

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:

The message to send to target when the timer fires.

The selector should have the following signature: timerFireMethod: (including a colon to indicate that the method takes an argument). The timer passes itself as the argument, thus the method would adopt the following pattern:

  • (void)timerFireMethod:(NSTimer *)timer

在Swift中签名必须

编辑:已更新以完全匹配您的代码

注意:Swift 2.2语法

class TextMessageViewController: UIViewController {
    var importTextMessage: AddMessageViewController // init'd somehow

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...

        // Note how selector matches *the name of the class*
        // As I understand it now, the sendMessage method
        // is declared in the AddMessageViewController class,
        // and importTextMessage is the name of the instance of that class.
        // And we're in a different class now, TextMessageViewController,
        // so using `self` does not make sense here.
        let timer = NSTimer(fireDate: date, interval: 60, target: importTextMessage,
            selector: #selector(AddMessageViewController.sendMessage(_:)), userInfo: params, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    }
}


class AddMessageViewController: UIViewController {
    // func must not be private
    func sendMessage(timer: NSTimer) {
       // And now for example
       print("params: \(timer.userInfo)")
    }
}

就您的 userInfo 字典而言,它是计时器对象的 属性,而不是目标函数本身的参数。

SECOND 错误是选择器语法未能使用声明 的class 的名称,而不是引用该 class 实例的某个实例变量的名称。在您的问题中包含更多上下文,以便更快地解决问题![​​=15=]

第三个 错误是您使用了错误的 class 名称。如果您使用 self,那么选择器 中的 class 名称必须与当前 class 的名称匹配。由于您确实希望消息 转到不同的 class,因此您必须改用 that 引用。查看更新后的代码。

我认为您仍然没有完全掌握对象引用及其类型,以及它们必须如何匹配,以及 self 如何只是对上下文对象的引用。