Search code examples
swiftexceptionruntime-errornstimer

Why am I getting this error message when I am using NSTimer to run function every x seconds?


I'm am using an NSTime to run a function every x amount of seconds as suggested here.

My issue is that I am getting this error message when ever the x amount of seconds is up and it is time to execute the function.

2015-04-06 11:55:51.898 myapp[21611:1186926] -[myapp.ViewController getJson(sharedData.jsonUrl)]: unrecognized selector sent to instance 0x7fff48761d60
2015-04-06 11:55:51.902 myapp[21611:1186926] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[myapp.ViewController getJson(sharedData.jsonUrl)]: unrecognized selector sent to instance 0x7fff48761d60'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000101497a75 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000102fefbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010149ed1d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x00000001013f69dc ___forwarding___ + 988
    4   CoreFoundation                      0x00000001013f6578 _CF_forwarding_prep_0 + 120
    5   Foundation                          0x00000001018cf844 __NSFireTimer + 83
    6   CoreFoundation                      0x00000001013ff6c4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    7   CoreFoundation                      0x00000001013ff285 __CFRunLoopDoTimer + 1045
    8   CoreFoundation                      0x00000001013c259d __CFRunLoopRun + 1901
    9   CoreFoundation                      0x00000001013c1bc6 CFRunLoopRunSpecific + 470
    10  GraphicsServices                    0x00000001055a0a58 GSEventRunModal + 161
    11  UIKit                               0x0000000101d2a580 UIApplicationMain + 1282
    12  maybe                               0x0000000100ed55ee top_level_code + 78
    13  myapp                               0x0000000100ed562a main + 42
    14  libdyld.dylib                       0x00000001037cb145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

I know that the function works as I have tested it on its own.

The code I am using to call the function with the NSTimer is:

override func viewDidLoad() {
    super.viewDidLoad()
    var timer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "getJson(sharedData.jsonUrl)", userInfo: nil, repeats: true)
}

I'm not sure why i am getting this error. I have tried removing the argument from the call and the function itself so that it is exactly the same as the code from the question on SO that I learnt this from but I have had no luck.

I am writing this in swift.

Here is a little bit more info. getJson is just a function that downloads a JSON file and appends some of the values to an array. sharedData is a singleton class - I am using it to store values that are needed to be used in different view controllers. jsonUrl is one of the variable in that class. So sharedData.jsonUrl is just getting that variable out of the class.\

EDIT:

This is the code I am trying to use now: var timer = NSTimer.scheduledTimerWithTimeInterval( 0.2, target: self, selector: "getJson:", userInfo: nil, repeats: true)

The exact error message is:

2015-04-06 16:16:56.160 myapp[22712:1284267] -[myapp.settingsViewController getJson:]: unrecognized selector sent to instance 0x7f8c88c7d810
2015-04-06 16:16:56.165 myapp[22712:1284267] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[myapp.settingsViewController getJson:]: unrecognized selector sent to instance 0x7f8c88c7d810'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010a491a75 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010bfe9bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010a498d1d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010a3f09dc ___forwarding___ + 988
    4   CoreFoundation                      0x000000010a3f0578 _CF_forwarding_prep_0 + 120
    5   Foundation                          0x000000010a8c9844 __NSFireTimer + 83
    6   CoreFoundation                      0x000000010a3f96c4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    7   CoreFoundation                      0x000000010a3f9285 __CFRunLoopDoTimer + 1045
    8   CoreFoundation                      0x000000010a3bc59d __CFRunLoopRun + 1901
    9   CoreFoundation                      0x000000010a3bbbc6 CFRunLoopRunSpecific + 470
    10  GraphicsServices                    0x000000010e59aa58 GSEventRunModal + 161
    11  UIKit                               0x000000010ad24580 UIApplicationMain + 1282
    12  myapp                               0x0000000109ed41ce top_level_code + 78
    13  myapp                               0x0000000109ed420a main + 42
    14  libdyld.dylib                       0x000000010c7c5145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

The get getJson function is:

func getJson() {
    let urlPath = sharedData.jsonUrl.absoluteString
    let url: NSURL = NSURL(string: urlPath!)!
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in

        if error != nil {
            // If there is an error in the web request, print it to the console
            println(error.localizedDescription)
        }

        var err: NSError?


        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary

        if err != nil {
            // If there is an error parsing JSON, print it to the console
            println("JSON Error \(err!.localizedDescription)")
        }

        let json = JSON(jsonResult)

        var teamCount = json["teamCount"].string! // Number in array
        var teamCountInt: Int = teamCount.toInt()! // Converts to integer

        for index in 0...teamCountInt - 1 { // loop for number in array
            let teamJson = json["teams"][index]["\(index)"].string! //
            sharedData.teamsArray.append(teamJson) // Appends to array in shared data
        }
        println(sharedData.teamsArray) // For debug - delete after
    })
    task.resume()
}

This function is uses Swifty-json.


Solution

  • Change the method getJson() as follows:

    class SomeGoodClassName {
        func getJson(timer: NSTimer) {
            //Directly use shareData.jsonUrl here to get json data
    
            //... more code
        }
    }
    

    NSTimer initialization

    let jsonLoader = SomeGoodClassName()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        var timer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: jsonLoader, selector: "getJson", userInfo: nil, repeats: true)
    }