Swift timer label recurring 9 - ios

I have created a simple timer in swift 3.
For some reason though, even though it works the label display too many numbers :S it displays a crazy amount of 9's. Is this to do with rounding?
Thanks, code below :)
var swiftTimer : Timer?
var swiftCounter: Double = 0.00
#IBOutlet weak var displayTimeLBL: UILabel!
#IBAction func start(_ sender: Any) {
swiftTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
}
#IBAction func stop(_ sender: Any) {
if swiftTimer != nil{
swiftTimer?.invalidate()
swiftCounter = 0.00
updateLabel()
swiftTimer = nil
}
}
func updateLabel(){
displayTimeLBL.text = String(swiftCounter)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func updateCounter(){
swiftCounter+=0.01
round(swiftCounter)
updateLabel()
}
enter image description here

Simplest Solution:
func updateCounter(){
swiftCounter+=0.01
round(swiftCounter)
swiftCounter = Double(round(100*swiftCounter)/100)
updateLabel()
}

If you want two fractions then you can use swiftCounter.round(2) instead of round(swiftCounter)
to update the text use:
displayTimeLBL.text = "\(swiftCounter.round(2))"
Here is the Double extension used:
extension Double {
func round(_ places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

Related

Updating label in time shows up all at once

I have a label that I would like to populate with a number of dots, each dot appearing in sequence, separated by 0.1 second
func setUpDots(numberOfDots: Int) {
for dots in 1...numberOfDots {
DispatchQueue.global(qos: .userInteractive).async {
DispatchQueue.main.async {
self.setLabelToDots(numberOfDots: dots)
}
usleep(100000) // wait 0.1 sec between showing each dot
}
}
}
func setLabelToDots(numberOfDots: Int) {
let dots = Array( repeating: ".", count: numberOfDots).joined()
myLabel.text = dots
myLabel.setNeedsDisplay()
}
But all the dots appear on the label at once
What should I do to get the right effect of the dots showing up with the specified delay between them?
Thanks for your feedback.
Basically, your for-loop is doing something similar to...
for dots in 1...numberOfDots {
self.setLabelToDots(numberOfDots: dots)
}
This is because each task is been allowed to execute at the same and the delay is having no effect on when the next one will run.
You "could" use a serial queue or you could use dependent operation queue, but a simpler solution might be to just use a Timer
This will allow you to setup a "delay" between ticks and treat the timer as a kind of pseudo loop, for example
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
let numberOfDots = 10
var dots = 0
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
myLabel.text = ""
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard timer == nil else {
return
}
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
}
#objc func tick() {
dots += 1
guard dots <= numberOfDots else {
timer?.invalidate()
timer = nil
dots = 0
return
}
numberOfDots(dots)
}
func numberOfDots(_ numberOfDots: Int) {
// You could just use string consternation instead,
// which would probably be quicker
let dots = Array( repeating: ".", count: numberOfDots).joined()
myLabel.text = dots
myLabel.setNeedsDisplay()
}
}
There are plenty of other examples about, but you should also have a look at the documentation for Timer

Swift 3 Counting up timer failed to show the updated number in UILabel

I have the following count up timer, but after i run the program, the UILable generate from 0 then to (). But the counter number is correct because i can see the printing log is correct.
May I know what's going wrong with the code.`
#IBOutlet weak var labelForBinaryCount: UILabel!
var timer = Timer()
var counter = 0
#IBAction func start() {
timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(Resting.updateCounter), userInfo: nil, repeats: true)
}
override func viewDidLoad() {
super.viewDidLoad()
labelForBinaryCount.text = String(counter)
}
func updateCounter() {
labelForBinaryCount.text = String(describing: counter += 1)
print(counter)
}
#IBAction func pauseButton(sender: AnyObject) {
timer.invalidate()
}
#IBAction func clearButton(sender: AnyObject) {
timer.invalidate()
counter = 0
labelForBinaryCount.text = String(counter)
}`
Try this:
func updateCounter() {
counter += 1
labelForBinaryCount.text = String(counter)
print(counter)
}
I think you understand. ;)

Simple Timer in iOS

I'm trying to make a simple timer in iOS using Swift.
The program is working fine but whenever my START UIButton is pressed the function of timer starts and runs multiple time as much as the button is pressed.
I want to disable the START UIButton as soon as the timer function starts so that it does not run multiple times.
Please help me for the same.
This is my code of ViewController
import UIKit
class ViewController: UIViewController {
var time = 0.0
var timer = Timer()
#IBOutlet weak var lbl: UILabel!
#IBAction func start(_ sender: UIButton)
{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: UIButton)
{
timer.invalidate()
}
#IBAction func reset(_ sender: UIButton)
{
timer.invalidate()
time = 0.0
lbl.text = ("0")
}
func action()
{
time += 0.1
lbl.text = String(time)
}
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.
}
}
To disable your button you can just set it's isUserInteractionEnabled property in start function:
#IBOutlet weak var startButton: UIButton!
#IBAction func start(_ sender: UIButton) {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
startButton.isEnabled = false
}
Then set it back to true in pause and reset methods:
#IBAction func pause(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
}
#IBAction func reset(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
//the rest of your code
}
The most reliable way to ensure that the timer is only started and stopped once is writing two methods which check the current state (timer is not nil if it's currently running):
var timer : Timer?
func startTimer()
{
guard timer == nil else { return }
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
// disable start button
}
func stopTimer()
{
guard timer != nil else { return }
timer!.invalidate()
timer = nil
// enable start button
}
In the methods you can enable/disable the button(s) accordingly.

Counting up/down numbers animation

I have an UIPageViewController with a number in the center of each VC in it.
I want that when I swipe from view to view, the number will begin at 0 and count up until it gets to the correct number (or if the number is negative - count down) like in this gif:
https://d13yacurqjgara.cloudfront.net/users/345970/screenshots/2126044/shot.gif
How can I do that?
Thank you!
You can use NSTimer to achieve this.
Here is example project I created for you.
Create layout like this:
Then in your ViewController do like so:
import UIKit
class ViewController: UIViewController {
#IBOutlet var countingLabel: UILabel!
var number = 0
var destinationNumber = 30
var timer: NSTimer!
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 startButtonTapped(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "countUp", userInfo: nil, repeats: true)
}
func countUp() {
if number < destinationNumber {
number += 1
countingLabel.text = "\(number)"
} else {
timer.invalidate()
}
}
}
It will work.
Do not overcomplicate with timers and invalidations, etc.
extension UILabel {
func countAnimation(upto: Double) {
let from: Double = text?.replace(string: ",", replacement: ".").components(separatedBy: CharacterSet.init(charactersIn: "-0123456789.").inverted).first.flatMap { Double($0) } ?? 0.0
let steps: Int = 20
let duration = 0.350
let delay = duration / Double(steps)
let diff = upto - from
for i in 0...steps {
DispatchQueue.main.asyncAfter(deadline: .now() + delay * Double(i)) {
self.text = "\(from + diff * (Double(i) / Double(delay)))"
}
}
}
}

My code seems to run too quickly

I am in the process of writing a Simon style memory game, the phase of the game where the program shows the user the current list of stuff to remember seems to run instantly.
The idea is to step through the list (in the code I have placed 1 of each item as debug data) and change the colour on screen for a set period then move to the next.
I thought using for each item in memory array and then call a simple procedure to check which one it is and then change colour for a set period then back to original.
The code I have added here will work if I put breaks in between the test change colour (grey) and the original colour. But for some reason the timer does not seem too work.
Any ideas ?
import UIKit
import Foundation
var gameisrunning = false
var playererror = false
var memoryArray = [Int]()
var currentScore = 0
var timer = NSTimer()
class ViewController: UIViewController {
#IBAction func startGameButton(sender: UIButton) {
if gameisrunning == false {
gameisrunning = true
memoryArray.append(1) //for debug
memoryArray.append(2) //for debug
memoryArray.append(3) //for debug
memoryArray.append(4) //for debug
print(memoryArray) //for debug
gameStart()
} else {
}
}
//these are to be implemented once i get the showing sequence sorted.
#IBAction func redButton(sender: UIButton) {
}
#IBAction func greenButton(sender: UIButton) {
}
#IBAction func yellowButton(sender: UIButton) {
}
#IBAction func blueButton(sender: UIButton) {
}
#IBOutlet weak var redLabel: UILabel!
#IBOutlet weak var greenLabel: UILabel!
#IBOutlet weak var yellowLabel: UILabel!
#IBOutlet weak var blueLabel: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
func addAnotherItemToMemory () {
// adds another item to the memory
memoryArray.append(Int(arc4random_uniform(4)+1))
}
func gameStart () {
// main body of game
showPlayerTheMemory()
}
func showPlayerTheMemory () {
// go through list and highlight the colors one at a time
for eachItem in memoryArray {
self.showColor(eachItem)
}
}
func pauseForAWhile(length: Double) {
timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: nil , userInfo: nil, repeats: false)
timer.invalidate()
}
func showColor(buttonItem: Int) {
//check to see which color, change to grey (test color) and back to original after a set time.
if buttonItem == 1 {
self.redLabel.backgroundColor = UIColor.grayColor()
pauseForAWhile(2)
self.redLabel.backgroundColor = UIColor.redColor()
print(buttonItem) //for debug
} else if buttonItem == 2 {
self.greenLabel.backgroundColor = UIColor.grayColor()
pauseForAWhile(2)
greenLabel.backgroundColor = UIColor.greenColor()
print(buttonItem) //for debug
} else if buttonItem == 3 {
self.yellowLabel.backgroundColor = UIColor.grayColor()
pauseForAWhile(2)
yellowLabel.backgroundColor = UIColor.yellowColor()
print(buttonItem) //for debug
} else if buttonItem == 4 {
self.blueLabel.backgroundColor = UIColor.grayColor()
pauseForAWhile(2)
blueLabel.backgroundColor = UIColor.blueColor()
print(buttonItem) //for debug
}
}
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.
}
}
New relevant code changed to :
func colorChange (){
self.redLabel.backgroundColor = UIColor.redColor()
self.blueLabel.backgroundColor = UIColor.blueColor()
self.yellowLabel.backgroundColor = UIColor.yellowColor()
self.greenLabel.backgroundColor = UIColor.greenColor()
}
func showColor(buttonItem: Int, length: Double) {
//check to see which color, change to grey (test color) and back to original after a set time.
if buttonItem == 1 {
self.redLabel.backgroundColor = UIColor.grayColor()
timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
print(buttonItem) //for debug
} else if buttonItem == 2 {
self.greenLabel.backgroundColor = UIColor.grayColor()
timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
print(buttonItem) //for debug
} else if buttonItem == 3 {
self.yellowLabel.backgroundColor = UIColor.grayColor()
timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
print(buttonItem) //for debug
} else if buttonItem == 4 {
self.blueLabel.backgroundColor = UIColor.grayColor()
timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
print(buttonItem) //for debug
}
}
I have been scratching head all day trying to solve this issue which is baffling me. I have copied the new latest code in below, please discard code above.
I have four labels coloured red blue green and yellow. The array which has test data of 4 3 2 1 inside needs to step through each item - change the colour of the label for x secs then return it to normal colour. I have tried NSTimer, I have tried the current delay as in the code attached. Am I missing something as to where I place the code - should it be under viewdidload ??? I have tried for loops and the current code example shows switch in case it acted differently - it didnt !!
What happens basically is simultaneously all labels go grey (test colour right now) and then all go original colour after the x sec delay.
I need some help before I go insane. I honestly know it is something basic but I just cannot figure it out.
import UIKit
import Foundation
var gameisrunning = false
var playererror = false
var memoryArray = [Int]()
var currentScore = 0
class ViewController: UIViewController {
#IBAction func startGameButton(sender: UIButton) {
if gameisrunning == false {
gameisrunning = true
memoryArray.append(4) //for debug
memoryArray.append(3) //for debug
memoryArray.append(2) //for debug
memoryArray.append(1) //for debug
print(memoryArray) //for debug
gameStart()
} else {
}
}
//these are to be implemented once i get the showing sequence sorted.
#IBAction func redButton(sender: UIButton) {
}
#IBAction func greenButton(sender: UIButton) {
}
#IBAction func yellowButton(sender: UIButton) {
}
#IBAction func blueButton(sender: UIButton) {
}
#IBOutlet weak var redLabel: UILabel!
#IBOutlet weak var greenLabel: UILabel!
#IBOutlet weak var yellowLabel: UILabel!
#IBOutlet weak var blueLabel: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
func addAnotherItemToMemory () {
// adds another item to the memory
memoryArray.append(Int(arc4random_uniform(4)+1))
}
func gameStart () {
// main body of game
showPlayerTheMemory()
}
func delayProg (){
//attempt 100093287492 to get a delay in program
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
self.blueLabel.backgroundColor = UIColor.blueColor()
self.yellowLabel.backgroundColor = UIColor.yellowColor()
self.greenLabel.backgroundColor = UIColor.greenColor()
self.redLabel.backgroundColor = UIColor.redColor()
}
}
func showPlayerTheMemory () {
// go through list and highlight the colors one at a time
for var i=0; i <= memoryArray.count-1; i++ {
self.showColor(memoryArray[i])
}
}
func showColor(buttonItem: Int) {
//check to see which color, change to grey (test color) and back to original after a set time.
switch (buttonItem) {
case 1:
self.redLabel.backgroundColor = UIColor.grayColor()
delayProg()
print(buttonItem) //for debug
case 2:
self.greenLabel.backgroundColor = UIColor.grayColor()
delayProg()
print(buttonItem) //for debug
case 3:
self.yellowLabel.backgroundColor = UIColor.grayColor()
delayProg()
print(buttonItem) //for debug
case 4:
self.blueLabel.backgroundColor = UIColor.grayColor()
delayProg()
print(buttonItem) //for debug
default:
print("error")
}
}
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.
}
}
Here is an example of proper implementation of NSTimer()
var myTimer = NSTimer()
func startTimer() {
myTimer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "myFunction", userInfo: nil, repeats: true)
}
func myFunction() {
myTimer.invalidate()
//do other stuff
}
//the selector is "myFunction", this will be the name of the function that you wish to call every time the timer reaches its specified intervl
//the interval in this case is 10 seconds. In my experience NSTimer is good down to the second but is not precise enough beyond that
//repeats: true ... this will tell the timer to repeat its action consistently firing the selector each time the given time interval is reached. If repeat is set to false then the timer only fires once
//use myTimer.invalidate to stop the timer and to stop calling the selector.
be sure to invalidate your timer or set repeats: false to make sure it doesn't go forever. Make sure your selector is spelled exactly the same as your function. if your function is func myFunction() then the selector should be "myFunction". Make sure you specify a valid time interval, which is taken as seconds.

Resources