4

I want to auto segue when a timer runs out.

I have a timer constructed here:

class Timer{
var timer = NSTimer();
// the callback to be invoked everytime the timer 'ticks'
var handler: (Int) -> ();
//the total duration in seconds for which the timer should run to be set by the caller
let duration: Int;
//the amount of time in seconds elapsed so far
var elapsedTime: Int = 0;
var targetController = WaitingRoomController.self


/**
:param: an integer duration specifying the total time in seconds for which the timer should run repeatedly
:param: handler is reference to a function that takes an Integer argument representing the elapsed time allowing the implementor to process elapsed time and returns void
*/
init(duration: Int , handler : (Int) -> ()){
    self.duration = duration;
    self.handler = handler;
}

/**
Schedule the Timer to run every 1 second and invoke a callback method specified by 'selector' in repeating mode
*/
func start(){
    self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "onTick", userInfo: nil, repeats: true);
}

/**
invalidate the timer
*/
func stop(){
    println("timer was invaidated from stop()")
    timer.invalidate();
}


/**
Called everytime the timer 'ticks'. Keep track of the total time elapsed and trigger the handler to notify the implementors of the current 'tick'. If the amount of time elapsed is the same as the total duration for the timer was intended to run, stop the timer.
*/


@objc func onTick() {
    //println("onTick")
    //increment the elapsed time by 1 second
    self.elapsedTime++;
    //Notify the implementors of the updated value of elapsed time
    self.handler(elapsedTime);
    //If the amount of elapsed time in seconds is same as the total time in seconds for which this timer was intended to run, stop the timer
    if self.elapsedTime == self.duration {
        self.stop();

    }
}
deinit{
    println("timer was invalidated from deinit()")
    self.timer.invalidate();
}

}

This is the view controller that I want to perform the segue on and how the timer starts:

class WaitingRoomController: UIViewController {

    private func handleSetAction(someTime: String){
       countDownLabel.text = setTime;
       let duration = Utils.getTotalDurationInSeconds(someTime);
       timer = Timer(duration: duration ){
          (elapsedTime: Int) -> () in
             println("handler called")
            let difference = duration - elapsedTime;
            self.countDownLabel.text = Utils.getDurationInMinutesAndSeconds(difference)
       }
       timer.start();
    }
}

I know that the code to auto segue is:

func doSegue(){
    self.performSegueWithIdentifier("asdf", sender: self)
}

but I do not know how to connect the timer and this function together.

Michael Ninh
  • 772
  • 2
  • 10
  • 23

2 Answers2

6

You need to use closures to achieve what you want, take a look in my class Timer.

import UIKit

class Timer: NSObject {

    var counter: Int = 0
    var timer: NSTimer! = NSTimer()

    var timerEndedCallback: (() -> Void)!
    var timerInProgressCallback: ((elapsedTime: Int) -> Void)!

    func startTimer(duration: Int, timerEnded: () -> Void, timerInProgress: ((elapsedTime: Int) -> Void)!) {

       if !(self.timer?.valid != nil) {
           let aSelector : Selector = "updateTime:"

           timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: aSelector, userInfo: duration, repeats: true)

           timerEndedCallback = timerEnded
           timerInProgressCallback = timerInProgress
           counter = 0
       }
    }

    func updateTime(timer: NSTimer) {

       ++self.counter
       let duration = timer.userInfo as! Int

       if (self.counter != duration) {
          timerInProgressCallback(elapsedTime: self.counter)
       } else {
          timer.invalidate()
          timerEndedCallback()
       }
    }
}

And then you can call the Timer class in the following way:

var timer = Timer()

timer.startTimer(5, timerEnded: { () -> Void in
        // Here you call anything you want when the timer finish.
        println("Finished")

        }, timerInProgress: { (elapsedTime) -> Void in
            println("\(Int(elapsedTime))")
})

The above class handle the use of the timer when it's already valid too and notice that the duration parameter is passed to the updateTime handler using the userInfo in the timer parameter.

I hope this help you.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • Apple has a very nice chapter in his book about [**Closures**](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html), it's worth to read it – Victor Sigler Jul 24 '15 at 23:07
  • I was looking at this and I finally think I understand closures! Thanks! I will implement and check back – Michael Ninh Jul 24 '15 at 23:09
  • Just kidding. I don't understand how to implement a closure at all for this. For example, in the "HandleSetAction" time = Time(Duration: Duration). How come the handler isn't passed as an argument? – Michael Ninh Jul 26 '15 at 02:14
  • @MichaelNinh Please if the answer solveryour question mark as accepted to it can help someone else. – Victor Sigler Aug 20 '15 at 14:17
1

change 'selector:"On Tick"' to 'selector:@selctor(doSegue)'. you can also look here for more information how to use NSTimer

Community
  • 1
  • 1
charris861
  • 54
  • 1