将 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 类型的参数。
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
如何只是对上下文对象的引用。
我正在使用 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 类型的参数。
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
如何只是对上下文对象的引用。