My game is supposed to be stopped after 60s. But nothing happens with my timer code.
var timer = NSTimer()
var counter:Int = 60
var labelCounter:SKLabelNode = SKLabelNode()
Here is the code in my GameScene class :
func startTimer()
{
timer = NSTimer.scheduledTimerWithTimeInterval(1.0
, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
}
func updateTimer(dt:NSTimer)
{
counter--
if counter == 0 {
timer.invalidate()
removeCountDownTimerView()
} else{
labelCounter.text = "\(counter)"
}
}
func removeCountDownTimerView()
{
scene.view.paused = true
}
thank you for your insight :-)
Try something like this....
override func viewDidLoad() {
super.viewDidLoad()
//calling the wait function
self.callForWait()
}
func callForWait(){
//setting the delay time 60secs.
let delay = 60 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) {
//call the method which have the steps after delay.
self.stepsAfterDelay()
}
}
func stepsAfterDelay(){
//your code after delay takes place here...
}
I had this in a game. Hope it helps:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
startGame()
}
var startTime = NSTimeInterval()
var timer = NSTimer()
var gameTime:Double = 10
func startGame() {
let aSelector : Selector = "updateTime"
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: aSelector, userInfo: nil, repeats: true)
startTime = NSDate.timeIntervalSinceReferenceDate()
}
func updateTime() {
var currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime = currentTime - startTime
var seconds = gameTime-elapsedTime
if seconds > 0 {
elapsedTime -= NSTimeInterval(seconds)
println("\(Int(seconds))")
} else {
timer.invalidate()
}
}
}
Related
I'm building an app in Swift 3. When I press start the first time my timer begins, but when I pause it and try to press start again, the timer does not budge. To give context, the timer, with an amount of time attached to it, is selected from a table. each time the timer load, the start button works initially.
protocol TimerViewControllerDelegate: class {
func viewController(_ controller: ViewController, didFinishEditing item: TaskData)
}
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var pauseButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var timerTaskName: UILabel!
#IBOutlet weak var timerTimeSetting: UILabel!
#IBOutlet weak var progressView: UIProgressView!
weak var delegate: TimerViewControllerDelegate?
var timerTask: TaskData?
var timer: Timer?
var progressViewSpeed: Double = 0.0
#IBAction func cancel(_ sender: Any) {
timer?.invalidate()
dismiss(animated: true, completion: nil)
delegate?.viewController(self, didFinishEditing: timerTask!)
}
#IBAction func startButtonTapped(_ sender: Any) {
timerTask?.startTime = Date()
runTimer()
if timerTask?.isTaskRunning == true {
runTimer()
self.startButton.isEnabled = false
self.pauseButton.isEnabled = true
} else {
//retrieve start time and run
timerTask?.startTime = Date()
runTimer()
self.startButton.isEnabled = false
self.pauseButton.isEnabled = true
}
}
func runTimer() {
guard timer == nil else {
return
}
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
}
#IBAction func pauseButtonTapped(_ sender: UIButton) {
if timerTask?.isTaskRunning == true {
timer?.invalidate()
if let timerTask = timerTask, timerTask.isTaskRunning {
// Calculate the difference between now and when the timerTask was started
let difference = Int(Date().timeIntervalSince(timerTask.startTime!))
timerTask.taskRemaining -= difference
if timerTask.taskRemaining == 0 {
// Do something when there's no time remaining on the task?
}
timerTask.startTime = nil
}
}
else {
timerTask?.startTime = Date()
runTimer()
self.pauseButton.setTitle("Pause",for: .normal)
}
self.startButton.isEnabled = true
self.pauseButton.isEnabled = false
}
/*
#IBAction func resetButtonTapped(_ sender: Any) {
timer.invalidate()
seconds = 60
self.timerLabel.text = timeString(time: TimeInterval(seconds))
if self.resumeTapped == true {
self.resumeTapped = false
self.pauseButton.setTitle("Pause",for: .normal)
}
isTimerRunning = false
pauseButton.isEnabled = false
startButton.isEnabled = true
}
*/
func updateTimer() {
guard let timerTask = timerTask else {
return
}
if timerTask.taskRemaining < 1 {
timer?.invalidate()
timer = nil
//Send alert to indicate "time's up!"
} else {
updateTime()
}
progressViewSpeed = 1 / Double(timerTask.taskRemaining)
progressView.progress += Float(progressViewSpeed)
}
func timeString(time:TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format:"%02i:%02i:%02i", hours, minutes, seconds)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let timerTask = timerTask else {
return
}
if timerTask.isTaskRunning {
startButton.isEnabled = false
pauseButton.isEnabled = true
runTimer()
} else {
startButton.isEnabled = true
pauseButton.isEnabled = false
}
timerTaskName.text = timerTask.task
updateTime()
self.progressView.transform = CGAffineTransform.identity.rotated(by: CGFloat.pi / 2).scaledBy(x: 1, y: 150)
}
func updateTime() {
guard let timerTask = timerTask else {
return
}
if let startTime = timerTask.startTime {
// Calculate the difference between now and when the timerTask was started
let difference = Int(Date().timeIntervalSince(startTime))
if timerTask.taskRemaining == difference {
// Do something when there's no time remaining on the task
timer?.invalidate()
timer = nil
}
timerLabel.text = timeString(time: TimeInterval(timerTask.taskRemaining - difference))
} else {
timerLabel.text = timeString(time: TimeInterval(timerTask.taskRemaining))
}
}
}
Once you've invalidated an NSTimer, you can't use it again. You should create the new object.
See here for more From NSTimer Docs
Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes and releases the timer, either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
You need to invalidate it and recreate it. "isPaused" bool to keep track of the state
var isPaused = true
var timer: Timer?
#IBAction func pauseResume(sender: AnyObject) {
if isPaused{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
pauseButton.isHidden = false
startButton.isHidden = true
isPaused = false
} else {
pauseButton.isHidden = true
startButton.isHidden = false
timer.invalidate()
isPaused = true
}
}
I'm trying to get output like so:
1 (then a one second delay)
Hello
2 (then a one second delay)
Hello
3 (then a one second delay)
Hello
But instead I get
1
2
3 (then a one second delay)
Hello
Hello
Hello
Here's my for loop invoking the NSTimer
var timer = NSTimer()
for i in 1...3 {
print("\(i)");
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MainVPScreenViewController.printTest), userInfo: nil, repeats: false)
}
And here's the selector method:
func printTest() {
print("Hello")
}
Thanks in advance for any help you can provide
Try this solution without NSTimer:
var i = 1
func printHello() {
print(i)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("Hello")
i +=1
if i <= 3 {
printHello()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
printHello()
}
I need 2 NSTimers to do this, this is my approach
class ViewController: UIViewController {
var i = 1
override func viewDidLoad() {
super.viewDidLoad()
beginPrinting()
}
func beginPrinting() {
var timer2 = NSTimer()
if(i <= 100)
{
timer2 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printWithDelay), userInfo: nil, repeats: false)
}
}
func printWithDelay()
{
var timer = NSTimer()
print("\(i)");
i += 1
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printTest), userInfo: nil, repeats: false)
}
func printTest() {
print("Hello")
beginPrinting()
}
}
Hope this helps you
Use timer with repeat to true. So in your view controller would be like this
var timer = NSTimer()
var counter = 0
var max = 10
let delay = 1 // in second
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self,
selector: #selector(self.printTest), userInfo: nil, repeats: true)
}
func printTest() {
counter += 1
print(counter)
print(hello)
if counter == maxNumber {
timer.invalidate()
}
}
This does it with repeat false, and is set up to be in a playground:
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
#objc class Foo: NSObject {
static var timer = NSTimer()
var i:Int
override init() {
Foo.timer = NSTimer()
i = 1
}
func schedule() {
print("\n\(i)");
i += 1
Foo.timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: #selector(printTest),
userInfo: nil,
repeats: false)
}
#objc func printTest() {
print("Hello")
if i < 5 {
schedule()
}
}
}
let bar = Foo()
bar.schedule()
This is a bit of a common question but most answers don't seem to work. I have a timer in my app that and I can start and re-start the timer easily. I am trying to pause and resume the timer but for now resuming only continues the timer from a timer that's greater than the one I resumed it at. Which probably means it continues counting in the background. This is my code :
//Timer Variables
var startTime = NSTimeInterval()
var timer = NSTimer()
var isTiming = Bool()
var isPaused = Bool()
func updatedTimer() {
let currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: NSTimeInterval = currentTime - startTime
let minutes = UInt8(elapsedTime / 60.0)
elapsedTime -= (NSTimeInterval(minutes) * 60)
let seconds = UInt8(elapsedTime)
elapsedTime -= NSTimeInterval(seconds)
let strMinutes = String(format: "%02d", minutes)
let strSeconds = String(format: "%02d", seconds)
workoutTime.text = "\(strMinutes) : \(strSeconds)"
}
#IBAction func startButtonTapped(sender: AnyObject) {
if !timer.valid {
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: #selector(TimedWorkoutViewController.updatedTimer), userInfo: nil, repeats: true)
startTime = NSDate.timeIntervalSinceReferenceDate()
}
isTiming = true
isPaused = false
}
#IBAction func pauseAndContinueButtonTapped(sender: AnyObject) {
if isTiming == true && isPaused == false {
timer.invalidate() //Stop the Timer
isPaused = true //isPaused
isTiming = false //Stopped Timing
pauseButton.setTitle("RESUME", forState: UIControlState.Normal) //Set Button to Continue state
print(startTime)
} else if isTiming == false && isPaused == true {
if !timer.valid {
timer.invalidate()
//timer = nil
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: #selector(TimedWorkoutViewController.updatedTimer), userInfo: nil, repeats: true)
}
isPaused = false
isTiming = true
pauseButton.setTitle("PAUSE", forState: UIControlState.Normal) //Set Button to Continue state
}
}
I have a custom timer application and dealt with the same issue. There are many ways to address this. You may want to track pausedTime like you do elapsedTime and subtract that from your other variables. This gives you some flexibility as well to show totalTime vs. elapsedTime, etc... My function is quite a bit different, so I retrofitted it to your setup.
Basically, pausing is different because you can pause/resume multiple times. So you need to track previous pauses, and current pause state and subtract from elapsed time (or total time, or whatever you want).
I tested this code and it worked. Give it a try and let me know:
import UIKit
class TimedWorkoutViewController: UIViewController {
#IBOutlet weak var pauseButton: UIButton!
#IBOutlet weak var startButton: UIButton!
var startTime = NSTimeInterval()
var timer = NSTimer()
var isTiming = Bool()
var isPaused = Bool()
var pausedTime: NSDate? //track the time current pause started
var pausedIntervals = [NSTimeInterval]() //track previous pauses
override func viewDidLoad() {
super.viewDidLoad()
}
func updatedTimer() {
let currentTime = NSDate.timeIntervalSinceReferenceDate()
var pausedSeconds = pausedIntervals.reduce(0) { $0 + $1 } //calculate total time timer was previously paused
if let pausedTime = pausedTime {
pausedSeconds += NSDate().timeIntervalSinceDate(pausedTime) //add current pause if paused
}
var elapsedTime: NSTimeInterval = currentTime - startTime - pausedSeconds //subtract time paused
let minutes = Int(elapsedTime / 60.0)
elapsedTime -= (NSTimeInterval(minutes) * 60)
let seconds = Int(elapsedTime)
elapsedTime -= NSTimeInterval(seconds)
let strMinutes = String(format: "%02d", minutes)
let strSeconds = String(format: "%02d", seconds)
workoutTime.text = "\(strMinutes) : \(strSeconds)"
}
#IBAction func startButtonTapped(sender: AnyObject) {
if !timer.valid {
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(TimedWorkoutViewController.updatedTimer), userInfo: nil, repeats: true)
startTime = NSDate.timeIntervalSinceReferenceDate()
}
isTiming = true
isPaused = false
pausedIntervals = [] //reset the pausedTimeCollector on new workout
}
#IBAction func pauseAndContinueButtonTapped(sender: AnyObject) {
if isTiming == true && isPaused == false {
timer.invalidate() //Stop the Timer
isPaused = true //isPaused
isTiming = false //Stopped Timing
pausedTime = NSDate() //asuuming you are starting a brand new workout timer
pauseButton.setTitle("RESUME", forState: UIControlState.Normal) //Set Button to Continue state
} else if isTiming == false && isPaused == true {
let pausedSeconds = NSDate().timeIntervalSinceDate(pausedTime!) //get time paused
pausedIntervals.append(pausedSeconds) // add to paused time collector
pausedTime = nil //clear current paused state
if !timer.valid {
timer.invalidate()
//timer = nil
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(TimedWorkoutViewController.updatedTimer), userInfo: nil, repeats: true)
}
isPaused = false
isTiming = true
pauseButton.setTitle("PAUSE", forState: UIControlState.Normal) //Set Button to Continue state
}
}
}
Here is some code I once used to track time
class TimeTracker : NSObject {
private var startTime:NSTimeInterval?
private var timer:NSTimer?
private var elapsedTime = 0.0
private var pausedTimeDifference = 0.0
private var timeUserPaused = 0.0
var delegate:TimeTrackerDelegate?
func setTimer(timer:NSTimer){
self.timer = timer
}
func isPaused() -> Bool {
return !timer!.valid
}
func start(){
if startTime == nil {
startTime = NSDate.timeIntervalSinceReferenceDate()
newTimer()
}
}
func pause(){
timer!.invalidate()
timeUserPaused = NSDate.timeIntervalSinceReferenceDate()
}
func resume(){
pausedTimeDifference += NSDate.timeIntervalSinceReferenceDate() - timeUserPaused;
newTimer()
}
func handleTimer(){
let currentTime = NSDate.timeIntervalSinceReferenceDate()
elapsedTime = currentTime - pausedTimeDifference - startTime!
delegate!.handleTime(elapsedTime)
}
func reset(){
pausedTimeDifference = 0.0
timeUserPaused = 0.0
startTime = NSDate.timeIntervalSinceReferenceDate()
newTimer()
}
private func newTimer(){
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target:self , selector: "handleTimer", userInfo: nil, repeats: true)
}
}
I am attempting to make a countdown timer that counts down from 60 seconds and then stops when it gets to 0. But for the timer keeps going into negative seconds. Any advice is appreciated. Code:
#IBOutlet var timeCounter: UILabel!
var second = 60
var timer = NSTimer()
var timerRunning = true
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setTimer()
timerCounting()
}
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
}
func timerCounting(){
if(timerRunning == true){
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setTimer"), userInfo: nil, repeats: true)
timerRunning = true
if second == 0 {
timerRunning = false
timer.invalidate()
}
}
}
You have to move the invalidation into the setTimer function since at its current location will never be triggered because timerCounting is only called once - in the beginning.
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
if second == 0 {
timerRunning = false
timer.invalidate()
}
}
play with this in playground
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
#objc class C:NSObject {
var timer: NSTimer?
var second = 5
func setTimer(){
if c.second < 0 {
print("the timer fires the last time here ...")
timer?.invalidate()
} else {
print(second)
second -= 1
}
}
}
let c = C()
func timerCounting(){
c.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: c, selector: Selector("setTimer"), userInfo: nil, repeats: true)
}
timerCounting()
I need launch the timer few times in sequence (one after another). And of course I need update Label with timer results.
For example, I have two periods (50 sec and 10 sec) and I need to make a series of periods: 50-10-50-10-50-10.
How can I do it?
import UIKit
class StartTimerViewController: UIViewController {
let firstPeriodTime = 50
let secondPeriodTime = 10
var currentPeriodTime: Int!
let repetitionTime = 3
var timer: NSTimer!
var timeCount = 0
#IBOutlet weak var timerLabel: UILabel!
// MARK: - IBAction method implementation
#IBAction func start(sender: AnyObject) {
// I know it's wrong... This is my question!!!!!
var i = 1
while i <= repetitionTime {
currentPeriodTime = firstPeriodTime
startTimer()
currentPeriodTime = secondPeriodTime
startTimer()
i = i + 1
}
}
// MARK: - Timer method implementation
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: "updateCounter", userInfo: nil, repeats: true)
print("timer start")
}
func updateCounter() {
if timeCount < currentPeriodTime {
timeCount++
let currentTime = Double(currentPeriodTime - timeCount)
timerLabel.text = timeString(currentTime)
}
else {
timer.invalidate()
timeCount = 0
}
}
func timeString(time:NSTimeInterval) -> String {
let minutes = Int(time) / 60
let seconds = time - Double(minutes) * 60
return String(format:"%02i:%02i",minutes,Int(seconds))
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Please use the code below
#IBOutlet weak var _lblTimer: UILabel!
var timer = NSTimer()
var intValue = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update50:", userInfo: nil, repeats: true)
}
func update50(timer : NSTimer){
intValue += 1
_lblTimer.text = intValue.description
if(intValue == 50){
intValue = 0
timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update10:", userInfo: nil, repeats: true)
}
}
func update10(timer : NSTimer){
intValue += 1
_lblTimer.text = intValue.description
if(intValue == 10){
intValue = 0
timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update50:", userInfo: nil, repeats: true)
}
}