将NSTimer目标消息发送到其他类;提取其userInfo参数

时间:2016-07-25 16:23:47

标签: ios swift selector nstimer

我正在使用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)

但这不会改变任何事情。

从发布的关于“无法识别的选择器发送到实例”的每个其他问题,响应是“在选择器中包含一个冒号,以便它知道从UserInfo中获取参数”,但我已经包含了这个,并且无法计算出了什么问题。

注意事项:

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

如果它意味着什么,则在调用sendMessage时代码失败。它实际上并没有使它成为sendMessage。

我收到一个奇怪的警告,说“String literal不是一个有效的objective-c选择器”

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

感谢您的帮助,我很感激。

编辑:这是运行计时器的函数://保存所有数据     @IBAction func saveText(sender:AnyObject){         var手机:双倍         var active:Int         var频率:双倍         var message:String         var date: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)

}

编辑:确切错误mssg:

无法识别的选择器发送到实例0x7ffe6b915460 2016-07-25 13:26:09.092 Harass Your Kate [53524:9000621] ***由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [Harass_Your_Kate.AddMessageViewController sendMessage:]:无法识别的选择器发送到实例0x7ffe6b915460 < / p>

2 个答案:

答案 0 :(得分:1)

来自doc

  

计时器将自己作为参数传递

所以你的计时器期望其他参数类型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])
}

此代码在我的标准视图控制器

中正常工作

答案 1 :(得分:0)

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

  

定时器触发时发送给目标的消息。

     

选择器应具有以下签名:timerFireMethod:   (包括冒号以指示该方法接受参数)。该   timer将自身作为参数传递,因此该方法将采用   以下模式:

     
      
  • (void)timerFireMethod:(NSTimer *)timer
  •   

在Swift中,签名必须

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

注意:Swift 2.2语法

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="288dp">

        <android.support.v7.widget.CardView
            android:id="@+id/card_view1"
            android:layout_width="match_parent"
            android:layout_height="288dp"
            android:elevation="3dp"
            card_view:cardCornerRadius="0dp"
            android:gravity="top">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/card"
                android:focusable="true"
                android:contextClickable="true"
                android:gravity="top"
                android:layout_alignParentBottom="true">

                <ImageView
                    android:id="@+id/thumbnail1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="?attr/selectableItemBackgroundBorderless"
                    android:clickable="true"
                    android:src="@drawable/ic_menu_send"
                    android:contextClickable="true"
                    android:layout_alignParentTop="true"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true" />

                <TextView
                    android:id="@+id/title1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="10dp"
                    android:paddingRight="25dp"
                    android:paddingTop="10dp"
                    android:textColor="@color/cardview_dark_background"
                    android:textSize="15dp"
                    android:layout_above="@+id/count1"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true" />

                <TextView
                    android:id="@+id/count1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingBottom="5dp"
                    android:paddingLeft="10dp"
                    android:paddingRight="25dp"
                    android:textSize="12dp"
                    android:layout_alignParentBottom="true"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true" />
            </RelativeLayout>

        </android.support.v7.widget.CardView>

    </LinearLayout>

</LinearLayout>

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

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

THIRD 错误是你使用了错误的类名。如果您使用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)") } } ,则选择器中的类名必须与当前类的名称相匹配。由于您确实希望消息转到其他类,因此您必须使用引用。查看更新的代码。

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