Start, Pause, Resume NSTimer Swift - swift2

I'd like to create a countdown timer feature where the user can pause and resume with the same button press. I know there have been several similar questions on SO including this one answered. However, I'm still stuck (2nd day). It seems that my timer is still ticking despite being invalidated.
Here is my code:
#IBOutlet weak var timerLabel: UILabel!
var duration: NSTimeInterval { return Double((exercise!.duration))! * 60 }
var interval: Double?
var timer = NSTimer()
var startTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: Double?
var timeLeft: Double?
var inProgress = false
var isPaused = false
var completionStatus = false
#IBAction func pressStart(sender: UIButton) {
if inProgress{
if isPaused {
resumeAnimation(timeLeftShapeLayer)
sender.setTitle("Pause", forState: UIControlState.Normal)
print("pressed resume, with \(timeLeft!) time left")
startTime = NSDate.timeIntervalSinceReferenceDate()
timer = NSTimer.scheduledTimerWithTimeInterval(timeLeft!, target: self, selector: #selector(PerformExerciseViewController.updateTime), userInfo: nil, repeats: false)
isPaused = false
} else {
pauseAnimation(timeLeftShapeLayer)
isPaused = true
sender.setTitle("Resume", forState: UIControlState.Normal)
elapsedTime = NSDate.timeIntervalSinceReferenceDate() - startTime
timeLeft = duration - elapsedTime!
timer.invalidate()
print("pressed pause, with \(timeLeft!) time left")
}
} else {
drawTimeLeftShape()
timeLeftShapeLayer.addAnimation(strokeIt, forKey: nil)
sender.setTitle("Pause", forState: UIControlState.Normal)
startTime = NSDate.timeIntervalSinceReferenceDate()
timer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: #selector(PerformExerciseViewController.updateTime), userInfo: nil, repeats: false)
inProgress = true
isPaused = false
}
When printing the time:
pressed pause, with 56.3997309803963 time left (long pause here, maybe 10 sec.)
pressed resume, with 56.3997309803963 time left (super short play time 0.1 sec.)
pressed pause, with 47.3651859760284 time left (seems like the time counted during the pause
Thanks for any help!!

I had calculated the remaining time wrong.
Instead of:
timeLeft = duration! - elapsedTime!
Use:
timeLeft = timeLeft! - elapsedTime!

Related

Thread 1: EXC_BAD_ACCESS when use selector with two args

It crash inside runTimer() because of two args. If I put only one or nothing - it works normal.
Crash forward to AppDelegate and error is
Thread 1: EXC_BAD_ACCESS (code=1, address=0x4)
var timer = Timer()
var seconds = Int()
#IBOutlet weak var twoMinView: UIView!
#IBOutlet weak var twoMinLabel: UILabel!
#objc func twoMinTimer() {
seconds = 120
runTimer(view: twoMinView, label: twoMinLabel)
}
#objc func runTimer(view: UIView, label: UILabel) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(MyViewController.updateTimer(view:withLabel:)), userInfo: nil, repeats: true)
}
#objc func updateTimer(view: UIView, withLabel label: UILabel) {
seconds -= 1
if seconds < 1 {
view.isHidden = true
timer.invalidate()
if view == twoMinView {
streamView.isHidden = false
}
}
label.text = timeString(time: TimeInterval(seconds))
}
#objc func timeString(time: TimeInterval) -> String {
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format: "%02i : %02i", minutes, seconds)
}
Just delete updateTimer and replace runTimer with next one
#objc func runTimer(view: UIView, label: UILabel) {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
if self.seconds < 1 {
view.isHidden = true
timer.invalidate()
if view == self.twoMinView {
self.streamView.isHidden = false
}
}
label.text = self.timeString(time: TimeInterval(self.seconds))
self.seconds -= 1
})
}

How to do a CountDown timer using Swift

Hello I am developing a countdown timer,which has to stop after 8 hours. Here it is:
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
var counter = 0
#IBOutlet weak var Label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Start(sender: AnyObject) {
counter = 28800
Label.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTimer"), userInfo: nil, repeats: true)
}
func updateTimer () {
counter -= 1
Label.text = String(counter)
}
#IBAction func Stop(sender: AnyObject) {
timer.invalidate()
}
}
But in stead of having 28800 seconds (which is 8hours)I want to display 08:00:00 , 07:59:59 , 07:59:58, so on... At the moment it is showing 28800, 28799, 28798, so on. Do you have an idea how to format it as a real clock (08:00:00)?
I had the same problem and pretty much a noob in xcode/swift - but after reviewing several sources, here's what I put together that works for me:
Replace your:
func updateTimer () {
counter -= 1
Label.text = String(counter)
}
With this:
func updateTimer () {
counter -= 1
let hours = Int(counter) / 3600
let minutes = Int(counter) / 60 % 60
let seconds = Int(counter) % 60
Label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
(xcode 8.1 warns about use of "let" or "var" for hours/minutes/seconds, but it still works)
Result look like:
00:00:00

Trying to multiply a variable from a slider to a NSTimer variable.

I made a timer and then I added a slider with a label that presented its value. What I want to do is have my last label (Moneyadded) show a multiplication of the slider value by the current amount of seconds with NStimer.
import UIKit
class ViewController: UIViewController {
var timercount = 0
var timerRunning = false
var timer = NSTimer()
var myVaribale: Int = 0
override func viewDidLoad() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
// fired once a second
myVaribale += 258
}
#IBOutlet weak var timerlabel: UILabel!
func counting(){
timercount += 1
timerlabel.text = "\(timercount)"
var timerValue = timercount.value
}
#IBAction func Clockin(sender: UIButton) {
if timerRunning == false{
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counting"), userInfo: nil, repeats: true)
timerRunning = true
}
}
#IBAction func Clockout(sender: UIButton) {
if timerRunning == true{
timer.invalidate()
timerRunning = false
}
}
#IBAction func Restart(sender: UIButton) {
timercount = 0
timerlabel.text = "0"
}
#IBOutlet weak var Slider: UISlider!
#IBOutlet weak var Label: UILabel!
#IBAction func valuechanged(sender: UISlider) {
var currentValue = Int(Slider.value)
Label.text = "\(currentValue)"
}
#IBOutlet weak var Moneyadded: UILabel!
\\this is for the label (text) that I want the NStimer to be multiplied by the slider value.
Change your counting function to the following:
/** Gets triggered once every second */
func counting(){
timercount += 1
timerlabel.text = "\(timercount)"
Moneyadded.text = "\(timercount * Int(Slider.value))"
}

Extra argument 'selector' in call

I'm trying to create a simple stopwatch app where the timer label increments when the startButton button is pressed. This is what I have:
#IBOutlet weak var timer: UILabel!
#IBAction func startButton(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(0.0025, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
}
var count = 0
func result() {
count++
timer.text=String(count)
}
I get the error "Extra argument 'selector' in call" but can't workout the syntax to do it properly.
Swift error messages are a little lacking at times. It should have said something like "NSTimer is not convertible to UILabel". You are assigning the timer you create to your IBOutlet timer which is a UILabel. The timer is an NSTimer. Just assign it to a different variable when you create it and all will be fine.
#IBAction func startButton(sender: AnyObject) {
let myTimer = NSTimer.scheduledTimerWithTimeInterval(0.0025, target: self, selector: "result", userInfo: nil, repeats: true)
}
As a shortcut, you can just use a string as a selector, so Selector("result") can be replaced by just "result".

Multiline Label On UIButton Swift

I've been trying to get a sync button to display Last Sync at (time&date). But All I get is one line with shortened text.
// Sync Button
syncBtn.frame = CGRectMake(15, height-60, 120, 40)
syncBtn.addTarget(self, action: "syncBtnPressed", forControlEvents: UIControlEvents.TouchUpInside)
syncBtn.setTitle("Last Sync: Never", forState: UIControlState.Normal)
syncBtn.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
syncBtn.layer.borderColor = UIColor.whiteColor().CGColor
syncBtn.layer.borderWidth = 1
syncBtn.layer.cornerRadius = 5
syncBtn.titleLabel?.font = UIFont(name: "Avenir", size: 10)
syncBtn.alpha = 0.5
syncBtn.titleLabel?.sizeToFit()
syncBtn.titleLabel?.textAlignment = NSTextAlignment.Center
syncBtn.titleLabel?.numberOfLines = 2
self.view.addSubview(syncBtn)
This is the function to get and set the date on the label
func printTimestamp(){
var timestamp = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .ShortStyle, timeStyle: .ShortStyle)
self.syncBtn.titleLabel?.text = ("Last Sync at: " + timestamp)
}
Anyone able to solve this problem?
create a UIButton with Multiple lines of text
Possible programtically
override func viewDidAppear(animated: Bool){
super.viewDidAppear(animated)
btnTwoLine.setTitle("Mulitple line", forState: UIControlState.Normal)
btnTwoLine.titleLabel!.lineBreakMode = NSLineBreakMode.ByWordWrapping;
}
Use SetTitle method instead of .text , when you use .text it sets the title text but the constraints are not updated accordingly hence you need to use SetTitle method and set the adjustsFontSizeToFitWidth to true
self.syncBtn.setTitle(timeStamp, forState: UIControlState.Normal)
self.syncBtn.titleLabel?.adjustsFontSizeToFitWidth = true

Resources