NSTimer does not work Swift

advertisements

I've seen this a couple of times before, but it never occured to me what might be wrong.

Firstly, I want to create the effect of scrambling numbers like they do in those hacking scenes in movies. So, I made an NSTimer to make my delays such that every 0.2 seconds, the numbers change. Then, I made another timer to tell my first timer to

invalidate()

after two seconds. My code is as follows:

import UIKit

class MainPage: UIViewController {

@IBOutlet var genericDeviceName: UITextField!
@IBOutlet var hackButton: UIButton!
@IBOutlet var rightNumber: UILabel!
@IBOutlet var leftNumber: UILabel!
@IBOutlet var detectionText: UILabel!

@IBAction func deviceNameEnter(sender: AnyObject) {
    detectionText.text = "Device detected: " + genericDeviceName.text!
    if genericDeviceName.text == "" {
        detectionText.text = "Error"
    }
    hackButton.alpha = 1
}

@IBAction func hackDevice(sender: AnyObject) {
    var tries = 0
    var timer = NSTimer()
    var timerStop = NSTimer()
    timer = NSTimer (timeInterval: 0.2, target: self, selector: "update", userInfo: nil, repeats: true)
    timerStop = NSTimer (timeInterval: 2, target: self, selector: "endTimer", userInfo: nil, repeats: true)

    let diceRoll = Int(arc4random_uniform(9) + 1)
    let diceRollSecond = Int(arc4random_uniform(9) + 1)

    UIView.animateWithDuration(0.25, animations:{
        self.hackButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))})

        func update() {leftNumber.text = String(diceRoll)
        rightNumber.text = String(diceRoll)
    print("it worked!")}

    func endTimer() {

    timer.invalidate()
        detectionText.text = "Access Granted!"
        timerStop.invalidate()
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.blackColor()
}

So... what went wrong? The last few times I tried using NSTimers, they didn't work either. Is my concept of an NSTimer wrong? Or is there an error in my code? There was no error message triggered, it was just that the timer did not trigger and the numbers did not change. Not even "it worked!" was printed to the logs. Please help by suggesting some code. Thank you in advance!

UPDATE

I've updated my code. Here it is:

 import UIKit

 class MainPage: UIViewController {

@IBOutlet var genericDeviceName: UITextField!

@IBOutlet var hackButton: UIButton!
@IBOutlet var rightNumber: UILabel!
@IBOutlet var leftNumber: UILabel!
@IBOutlet var detectionText: UILabel!
@IBAction func deviceNameEnter(sender: AnyObject) {

    detectionText.text = "Device detected: " + genericDeviceName.text!

    if genericDeviceName.text == "" {detectionText.text = "Error"}

    hackButton.alpha = 1

}
let diceRoll = Int(arc4random_uniform(9) + 1)
    let diceRollSecond = Int(arc4random_uniform(9) + 1)

func update(timer: NSTimer) {leftNumber.text = String(diceRoll)
    rightNumber.text = String(diceRoll)
    print("it worked!")}

func endTimer(timerStop: NSTimer) {

    timer.invalidate()
    detectionText.text = "Access Granted!"
    timerStop.invalidate()}

@IBAction func hackDevice(sender: AnyObject) {

    var timer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "update:", userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    var timerStop = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "endTimer:", userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(timerStop, forMode: NSRunLoopCommonModes)

    UIView.animateWithDuration(0.25, animations:{
        self.hackButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))})

    }

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.backgroundColor = UIColor.blackColor()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

 }

Currently, it seems that the function "endTimer" does not work, due to the variable "timer" not being recognised. Please help. Thank you all so much for your time!


You should move your functions out of hackDevice. Nested functions like this are generally not used in Swift.

For example:

let diceRoll = Int(arc4random_uniform(9) + 1)
let diceRollSecond = Int(arc4random_uniform(9) + 1)
var timer = NSTimer()
@IBAction func hackDevice(sender: AnyObject) {

    var tries = 0
    var timer = NSTimer()
    var timerStop = NSTimer()
    timer = NSTimer (timeInterval: 0.2, target: self, selector: "update", userInfo: nil, repeats: true)
    timerStop = NSTimer (timeInterval: 2, target: self, selector: "endTimer", userInfo: nil, repeats: true)

    UIView.animateWithDuration(0.25, animations:{
        self.hackButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))})
}

func update() {
    leftNumber.text = String(diceRoll)
    rightNumber.text = String(diceRoll)
    print("it worked!")
}

func endTimer() {
    timer.invalidate()
    detectionText.text = "Access Granted!"
    timerStop.invalidate()
}