Text to count These are the numbers I like to count down, S= start, O= stop, R= reset. Added for simpler functionality but do not want to use them.
I'm trying to set a countdown timer on this app, but I'm having issues getting it to work with the tutorials I've seen. My guess is that this version of swift has different functions, Xcode version 9.4.
The goal is to have a counter for a year, days, and time, as each runs out it stops and counts the next, preferably I want random numbers, no start or stop buttons, start can be once app opens or if the user accepts on a previous screen.
I have tried these methods, but they either don't do anything or force me to use #object func counter(), I believe the timer is not calling the function once its an object, I don't know how to call it.
import UIKit
class ViewController: UIViewController {
var seconds = 30
var timer = Timer()
//these are others I will implement later
#IBOutlet weak var YRS: UILabel!
var yrs = 1
#IBOutlet weak var DAY: UILabel!
var day = 3
#IBOutlet weak var HRS: UILabel!
var hrs = 5
#IBOutlet weak var SEC: UILabel!
var sec = 35
#IBOutlet weak var MIN: UILabel!
//timer function, I believe I have to change #selector as is not
calling the counter func
#IBAction func str(_ sender: UIButton) {
//I have also used just counter but nothing changes :/
timer = Timer.init(timeInterval: 60.0, target: self, selector:
#selector(ViewController.counter), userInfo: nil, repeats: true)
MIN.text = String (seconds)
}
//stop button
#IBAction func sto(_ sender: Any) {
}
//reset button
#IBAction func rst(_ sender: Any) {
}
//counter here -1
#objc func counter(){
seconds -= 1
MIN.text = String(seconds)
if (seconds == 00) {
timer.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
//Something I have tried but did not work
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
}
func update() {
if(min > 0) {
MIN.text = String(min-1)
}
}
//No errors found, the screen is updated with the value but it does not change.
This was a test in Playground. But you can of course also use it in your viewDidLoad Method. It is not ready, you just have to add code where i commented it (add code here...). I set the timer to 0.1 seconds, so that i could test it.
var YRS = UILabel()
var yrs = 1
var DAY = UILabel()
var day = 3
var HRS = UILabel()
var hrs = 5
var SEC = UILabel()
var sec = 35
var MIN = UILabel()
var min = 15
YRS.text = "years \(yrs)"
YRS.sizeToFit()
view.addSubview(YRS)
DAY.text = "day \(day)"
DAY.sizeToFit()
DAY.frame.origin.y = 30
view.addSubview(DAY)
HRS.text = "HRS \(hrs)"
HRS.sizeToFit()
HRS.frame.origin.y = 60
view.addSubview(HRS)
MIN.text = "min \(day)"
MIN.sizeToFit()
MIN.frame.origin.y = 90
view.addSubview(MIN)
SEC.text = "SEC \(sec)"
SEC.sizeToFit()
SEC.frame.origin.y = 120
view.addSubview(SEC)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
sec = sec - 1
if sec < 0 { sec = 59
min = min - 1
if min < 0 { min = 59
hrs = hrs - 1
if hrs < 0 {
hrs = 23
HRS.text = "HRS \(hrs)"
HRS.sizeToFit()
// add code here for day ...
}
}
MIN.text = "min \(min)"
MIN.sizeToFit()
}
SEC.text = "sec \(sec)"
SEC.sizeToFit()
}
Related
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "Hard" : 12]
#IBOutlet weak var eggCountdown2: UILabel!
#IBOutlet weak var eggCountDown: UILabel!
#IBOutlet weak var eggCountdown3: UILabel!
var count1 = 7
var count2 = 5
var count3 = 12
override func viewDidLoad() {
super.viewDidLoad()
var timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
}
#objc func update() {
switch UILabel() {
case eggCountDown:
print("\(count1) seconds to get your medium egg")
count1 -= 1
case eggCountdown2 :
print("\(count2) seconds to get your soft egg")
count2 -= 1
case eggCountdown3 :
print("\(count3) seconds to get your fucking hard egg")
count3 -= 1
default:
print ("Error")
}
}
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle!
print(eggTimes [hardness]!)
}
}
I am getting "Error" countdowns in my EggTimer code. It's supposed to be counting down the time each egg takes. I have tried multiple ways to tackle this but always ended with up this. Also I have been scraping Apple documentation for the same but still cannot find the relevant answer.
Screen shot:
Rather than switching on an unrelated label – which cannot work – create a property for the hardness
var hardness = ""
and one counter is sufficient as you apparently not going to run two timers simultaneously.
var counter = 0
and assign both values in hardnessSelected
#IBAction func hardnessSelected(_ sender: UIButton) {
self.hardness = sender.currentTitle!
self.counter = eggtimes[hardness]!
print(counter)
}
Then switch this way
#objc func update() {
switch hardness {
case "Medium":
print("\(count1) seconds to get your medium egg")
counter -= 1
case "Soft" :
print("\(count2) seconds to get your soft egg")
counter -= 1
case "Hard" :
print("\(count3) seconds to get your fucking hard egg")
counter -= 1
default:
print ("Error")
}
}
And you need to check when the countdown ends and to start the timer in the IBAction. And to avoid bad cooking experience set the repeat interval to 60 (one minute) or multiply the egg times by 300.
I am new to learning swift and my jitterclick style game will not reset after it is complete. Despite already setting the isTimerRunning to false, nothing i have done seems to work. The game is supposed to begin when you press start, start a count down timer from 10, count your number of clicks, and give you a click per second score at the end. This is my first app without a tutorial and appreciate all the help i can get. Thanks
import UIKit
var score = 0
var timer = Timer()
var cps = score / 10
var time = 10.00
var isTimerRunning = false
var isGameComplete = true
var realTime = 0.0
class ViewController: UIViewController {
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var clickingButton: UIButton!
#IBOutlet weak var CPSLabelTxt: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var scoreLabelTxt: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
resetButton.isHidden = true
resetButton.isEnabled = false
CPSLabelTxt.isHidden = true
scoreLabelTxt.isHidden = false
scoreLabelTxt.text = "Press Start to begin"
}
#IBAction func resetButtonDidTap(_ sender: Any){
resetButton.isEnabled = false
startButton.isEnabled = true
time = 10.0
timerLabel.text = "10.00"
isTimerRunning = false
}
#IBAction func clickingButtonDidTap(_ sender: Any) {
if !isGameComplete {
score += 1
scoreLabelTxt.text = "\(score)"
}
}
//Start button is pressed
#IBAction func startButtonDidTap(_ sender: Any) {
isGameComplete = false
startButton.isEnabled = false
//Count down timer begins
if !isTimerRunning{
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(runTimer), userInfo: nil, repeats: true)
isTimerRunning = true
}
}
//logic for timer
#objc func runTimer(){
time -= 0.01
realTime = round(100 * time) / 100
timerLabel.text = "\(realTime)"
if time < 0.0 {
isTimerRunning = false
timerLabel.text = "0.00"
isGameComplete = true
resetButton.isHidden = false
CPSLabelTxt.isHidden = false
scoreLabelTxt.isHidden = false
scoreLabelTxt.text = "\(score)"
CPSLabelTxt.text = "\(cps)"
time = -2
}
}
}
Put timer.invalidate() in your resetButtonDidTap(_ sender: Any) function. This stops the timer from running.
For some reason the stopwatch looks to be alright, but when compared to the real deal it goes way too fast. I don't understand what I should do. Is it the timeInterval that I should change? I would like it to show millisecond, second and minutes, but everything I try just makes it worse.. Thank you
import UIKit
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var minutes: UILabel!
#IBOutlet weak var seconds: UILabel!
#IBOutlet weak var milliSecondsLabel: UILabel!
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var pauseButton: UIButton!
// Variables
var timer = Timer()
var time: Int = 0
var running: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
roundButtons()
}
#IBAction func resetTimer(_ sender: Any) {
timer.invalidate()
time = 0
updateUI()
running = false
}
#IBAction func startTimer(_ sender: Any) {
if running {
return
} else {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerDidEnd), userInfo: nil, repeats: true)
running = true
}
}
#IBAction func pauseTimer(_ sender: Any) {
timer.invalidate()
running = false
}
func roundButtons() {
resetButton.layer.cornerRadius = resetButton.frame.height / 2
startButton.layer.cornerRadius = startButton.frame.height / 2
pauseButton.layer.cornerRadius = pauseButton.frame.height / 2
}
#objc func timerDidEnd() {
time += 1
updateUI()
}
func updateUI() {
var min: Int
var sec: Int
var mil: Int
min = time / (60*60)
sec = (time/60)%60
mil = time & 60
minutes.text = String(min)
seconds.text = String(sec)
milliSecondsLabel.text = String(mil)
}
}
I'd suggest two things:
Don’t try to count the time elapsed yourself. Capture the start time and calculate the elapsed time from that. You can use Date method timeIntervalSince, or, because that's not guaranteed to return monotonically increasing values, use CACurrentMediaTime, like below.
Rather than having a timer with an arbitrary 100 updates per second, instead use a CADisplayLink, which is optimally timed for device screen refresh rates.
E.g.:
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var minutesLabel: UILabel!
#IBOutlet weak var secondsLabel: UILabel!
#IBOutlet weak var milliSecondsLabel: UILabel!
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var pauseButton: UIButton!
// Variables
private weak var displayLink: CADisplayLink?
private var startTime: CFTimeInterval?
private var elapsed: CFTimeInterval = 0
private var priorElapsed: CFTimeInterval = 0
override func viewDidLoad() {
super.viewDidLoad()
setFonts()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
roundButtons()
}
#IBAction func resetTimer(_ sender: Any) {
stopDisplayLink()
elapsed = 0
priorElapsed = 0
updateUI()
}
#IBAction func startTimer(_ sender: Any) {
if displayLink == nil {
startDisplayLink()
}
}
#IBAction func pauseTimer(_ sender: Any) {
priorElapsed += elapsed
elapsed = 0
displayLink?.invalidate()
}
}
private extension ViewController {
func startDisplayLink() {
startTime = CACurrentMediaTime()
let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
displayLink.add(to: .main, forMode: .common)
self.displayLink = displayLink
}
func stopDisplayLink() {
displayLink?.invalidate()
}
#objc func handleDisplayLink(_ displayLink: CADisplayLink) {
guard let startTime = startTime else { return }
elapsed = CACurrentMediaTime() - startTime
updateUI()
}
func updateUI() {
let totalElapsed = elapsed + priorElapsed
let hundredths = Int((totalElapsed * 100).rounded())
let (minutes, hundredthsOfSeconds) = hundredths.quotientAndRemainder(dividingBy: 60 * 100)
let (seconds, milliseconds) = hundredthsOfSeconds.quotientAndRemainder(dividingBy: 100)
minutesLabel.text = String(minutes)
secondsLabel.text = String(format: "%02d", seconds)
milliSecondsLabel.text = String(format: "%02d", milliseconds)
}
func roundButtons() {
resetButton.layer.cornerRadius = resetButton.bounds.height / 2
startButton.layer.cornerRadius = startButton.bounds.height / 2
pauseButton.layer.cornerRadius = pauseButton.bounds.height / 2
}
func setFonts() {
minutesLabel.font = UIFont.monospacedDigitSystemFont(ofSize: minutesLabel.font.pointSize, weight: .regular)
secondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: secondsLabel.font.pointSize, weight: .regular)
milliSecondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: milliSecondsLabel.font.pointSize, weight: .regular)
}
}
That yields:
Completely unrelated, but anything dependent upon the size of views (e.g. the corner rounding) really belongs in viewDidLayoutSubviews, not viewDidLoad.
I am trying to display different text within a label after a period of time using a timer, but cant increment the element of my custom type array.
Here is the code:
import UIKit
class WorkWorkoutViewOne: UIViewController {
#IBOutlet weak var exerciseTitle: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var instructionsLabel: UILabel!
#IBOutlet weak var exerciseImage: UIImageView!
var counter = 15
var timer: NSTimer?
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
let image: UIImage = workoutExercisesShuffled[0].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[0].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[0].instructions
instructionsLabel.text = instructionsTitle
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerAction", userInfo: nil, repeats: true)
}
var timerTwo: NSTimer?
var counterTwo = 15
func timerAction() {
--counter
timerLabel.text = "\(counter)"
if (counter == 0) {
timer?.invalidate()
let image: UIImage = workoutExercisesShuffled[1].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[1].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[1].instructions
instructionsLabel.text = instructionsTitle
timerLabel.text = "\(counterTwo)"
var timerTwo = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerActionTwo", userInfo: nil, repeats: true)
}
}
Repeating this method using timerThree, timerFour etc. seems clumbsy and unnecessary, so would like a way to increment the array values rather than having to call seperately in different functions.
Try this, it uses two methods and an index.
Workflow
Initially index is set to 0 and counter is set to 15.
updateExercise() is called.
The exercise UI is updated.
If index is 0 the timer is created.
timerAction() is called after the timer fires.
The counter is decremented and the counter label is updated.
If counter is 0 and index is equal to the number of exercises -1 the timer is invalidated.
If counter is 0 and index < number of exercises -1 index is incremented, counter is reset to 15 and updateExercise() is called again.
var counter = 15
var index = 0
var timer: NSTimer?
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
updateExercise()
}
func updateExercise() {
let image: UIImage = workoutExercisesShuffled[index].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[index].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[index].instructions
instructionsLabel.text = instructionsTitle
if index == 0 {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerAction", userInfo: nil, repeats: true)
}
}
func timerAction() {
counter -= 1
timerLabel.text = "\(counter)"
if (counter == 0) {
if index == workoutExercisesShuffled.count - 1 {
timer!.invalidate()
timer = nil
} else {
index += 1
counter = 15
updateExercise()
}
}
}
I did not test this, but it should work.
import UIKit
class WorkWorkoutViewOne: UIViewController {
#IBOutlet weak var exerciseTitle: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var instructionsLabel: UILabel!
#IBOutlet weak var exerciseImage: UIImageView!
var count = 15
var index = 0
var timer: NSTimer
var countdown: NSTimer
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
// TODO: load your exercises
var timer = NSTimer.scheduledTimerWithTimeInterval(15, target: self, selector: "displayNewExercise", userInfo: nil, repeats: true)
}
func displayNewExercise() {
countdown = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "displayCountdown", userInfo: nil, repeats: true)
if (index < workoutExercisesShuffled.count) {
exerciseImage.image = workoutExercisesShuffled[index].filename!
exerciseTitle.text = workoutExercisesShuffled[index].name
instructionsLabel.text = workoutExercisesShuffled[index].instructions
++index
}
else {
timer.invalidate()
countdown.invalidate()
}
}
func displayCountdown() {
if(count > 0) {
countDownLabel.text = String(--count)
}
else {
countdown.invalidate()
count = 15
}
}
}
Don't repeat yourself. A certain task can be done only by one function, the code for this particular task must not be elsewhere.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Hey so I'm new to coding and I placed a button on my View Controller (Drag and drop). The button is not responding to touch or anything and appears 'static.' I'm tired and exhausted. Someone help? Thank you so much!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lblMadeToday: UILabel!
#IBOutlet weak var Cents: UILabel!
var timer = NSTimer()
var hourlyWage : CGFloat = CGFloat (hourlyPrice)
var timeTo1 : CGFloat = 0
var time : Float = 0
var earnt : CGFloat = 0
var madeToday : CGFloat = 0
#IBAction func btnClick(sender: AnyObject) {
}
func tick() {
earnt = CGFloat (time)/timeTo1
lbl1.text = NSString(format: "%.2f", earnt) as String
if (earnt >= 1) {
time = 0
madeToday++
lblMadeToday.text = madeToday.description
}
time++
}
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
timeTo1 = CGFloat (360000)/hourlyWage;
println("view Loaded :)")
NSNotificationCenter.defaultCenter().addObserver(self, selector:"doYourStuff", name:
UIApplicationWillEnterForegroundNotification, object: nil)
}
func doYourStuff(){
var nowHour = NSCalendar.currentCalendar().component(.CalendarUnitHour, fromDate: NSDate())
var nowMinute = NSCalendar.currentCalendar().component(.CalendarUnitMinute, fromDate: NSDate())
var nowSecond = NSCalendar.currentCalendar().component(.CalendarUnitSecond, fromDate: NSDate())
var time1 = (nowHour - globalHour) * 60
var time2 = (nowMinute - globalMinute)
var time3 : CGFloat = (CGFloat(nowSecond)-CGFloat(globalSecond))/60
var timeInMinutesGone : CGFloat = CGFloat(time1) + CGFloat(time2) + CGFloat(time3)
println (timeInMinutesGone)
madeToday = (timeInMinutesGone / 60) * (CGFloat(hourlyWage))
var ef : Int = Int(madeToday)
lblMadeToday.text = String(ef)
}
#IBAction func btnPress(sender: AnyObject) {
println("hello")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your NSTimer is being executed in the UI thread every 0.01 seconds. This could be detrimental for your app. It's likely that if you execute NSTimer in a background thread, your button will work as expected.
One way to add your NSTimer to background could be:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
NSRunLoop.currentRunLoop().run()
})