Q:

NSTimer not working Swift

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!

A:

A few things: The selector for an NSTimer should end in a colon (e.g. "update:" or "endTimer:" And the function should take a single parameter: An NSTimer.
Second, the function that the timer calls must be a top-level function of the target. Your update method is a local function of your hackDevice, function, which won't work.
Third, you need to use scheduledTimerWithTimeInterval, as in ShahiM's answer:
var timer = NSTimer.scheduledTimerWithTimeInterval(
  0.4, 
  target: self, 
  selector: "update:", 
  userInfo: nil, 
  repeats: true)

That code crashes if the function in your selector is a nested function because it's not visible to the timer.
Finally, it looks like you need to move the variables diceRoll and diceRollSecond out of your hackDevice function and make them instance variables of your class.

A:

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()
}

A:

Try using this :
var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)

Also move your update and endTimer methods outside the hackDevice method.
Explanation :
From Apple docs :

Use the timerWithTimeInterval:invocation:repeats: or timerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer object without scheduling it on a run loop. (After creating it, you must add the timer to a run loop manually by calling the addTimer:forMode: method of the corresponding NSRunLoop object.) 

.

Use the scheduledTimerWithTimeInterval:invocation:repeats: or scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: class method to create the timer and schedule it on the current run loop in the default mode. 

So in your code, you only create the timer but it does not start running. You have to either call the addTimer(_ timer: NSTimer,forMode mode: String) to start the timer or you can simply use scheduledTimerWithTimeInterval to launch the timer right away.

