I am a complete beginner and am starting to learn the Swift programming language. I'm following a tutorial on Udemy and am having some problems with setting up a timer.
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var timer1 = Timer()
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
label.text = String(counter)
}
#IBAction func start(_ sender: Any) {
timer1 = Timer(timeInterval: 1, target: self, selector: #selector(tim), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: Any) {
timer1.invalidate()
}
#IBAction func restart(_ sender: Any) {
timer1.invalidate()
counter = 0
label.text = String(counter)
}
#objc func tim() {
counter += 1
label.text = String(counter)
}
}
This is my code but the timer is not working. Please tell me where im going wrong.
You need to add timer to RunLoop
RunLoop.current.add(timer1, forMode: .commonModes)
Or use scheduledTimer
timer1 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(tim), userInfo: nil, repeats: true)
Also in your restart function you need to do it again, because now you are just invalidating it and not starting again.
Related
I am making timer. I cannot figure out how to make start button tapped only once as it is starting to count. And at stop button timer.invalidate() does not work
#IBAction func start(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(W1ViewController.counter), userInfo: nil, repeats: true)
}
#IBOutlet weak var stopOutlet: UIButton!
#IBAction func stop(_ sender: Any) {
seconds = 30
label.text = "\(seconds)"
timer.invalidate()
audioPlayer.stop()
}
Just disable the button
#IBAction func start(_ sender: Any) {
stopOutlet.isEnabled = false
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(W1ViewController.counter), userInfo: nil, repeats: true)
}
Then re-enable when needed:
stopOutlet.isEnabled = true
UIButton extends UIControl. UIControl provides this and alot more functionality to all controls.
I want to access myTimer variable from startTimer() function inside my backBtnPressed() function. Basically i want to add this code myTimer.invalidate() inside my backBtnPressed() function. How can i achieve that?
func startTimer() {
var myTimer = Timer.scheduledTimer(timeInterval: 3.0,
target: self,
selector: #selector(scrollToNextCell),
userInfo: nil,
repeats: true)
}
#IBAction func backBtnPressed(_ sender: UIButton) {
audioPlayer.stop()
}
As it stands now, you cannot access myTimer variable outside startTimer(), because it is outside the scope. For that, you need to declare myTimer as a Class variable. Them, you need to initialize it, as you are doing, and them you can access whatever you want inside the Class. Also don't forget to call startTimer, or it will return nil.
It looks more or less like this:
class YourViewController: ViewController {
var myTimer: Timer?
//some of your functions here
//...
override func viewDidLoad() {
super.viewDidLoad()
//...
startTimer()
}
func startTimer() {
myTimer = Timer.scheduledTimer(timeInterval: 3.0,
target: self,
selector: #selector(yourFunction),
userInfo: nil,
repeats: true)
}
#IBAction func backBtnPressed(_ sender: UIButton) {
//do whatever you want
myTimer.invalidate()
}
}
Simple make your timer a property:
class MyClass {
var timer: Timer?
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(scrollToNextCell), userInfo: nil, repeats: true)
}
#IBAction func backBtnPressed(_ sender: UIButton) {
audioPlayer.stop()
timer.//do something with timer
}
}
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.
I know this is asked a lot but I've tried a lot of the other solutions on here and I can't seem to get it right.
So, I have a class that counts down, and at the end of the countdown a new view begins.
Here is the countdown class:
import Foundation
import UIKit
class CountdownController: UIViewController {
// MARK: Properties
#IBOutlet weak var countDownLabel: UILabel!
var count = 3
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
if(count > 0) {
countDownLabel.text = String(count--)
}
else {
self.performSegueWithIdentifier("goestoMathTest", sender: self)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Actions
}
and the error that comes up after the MathTestController shows is:
2016-05-26 23:43:48.579 TraderMathTestiOS[18654:951105] Warning: Attempt to
present <TraderMathTestiOS.MathTestController: 0x7fca824be7d0> on
<TraderMathTestiOS.CountdownController: 0x7fca824b9d70> whose view is not in
the window hierarchy!
**EDIT: So I tried another changing a few things and I think I narrowed down the issue. I changed the timer to be in viewDidLoad() and changed the repeats to 'false' and now MathTestController appears after 1 second with no warnings showing up. Here's the changed code:
override func viewDidLoad() {
super.viewDidLoad()
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: false)
}
func update() {
self.performSegueWithIdentifier("goestoMathTest", sender: self)
if(count > 0) {
countDownLabel.text = String(count--)
}
else {
self.performSegueWithIdentifier("goestoMathTest", sender: self)
}
}
I think the reason the error shows up is because the timer keeps repeating in the CountdownController even after MathTestController is called. Anybody know how to get my original functionality ( A timer that counts '3, 2, 1') without the error? Maybe I need to kill the timer somehow?
I fixed this finally. For anyone wondering, if your timer repeats you need to invalidate it if you're starting a new view. Here's the fixed code:
class CountdownController: UIViewController {
// MARK: Properties
#IBOutlet weak var countDownLabel: UILabel!
var timer = NSTimer()
var count = 3
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
if(count > 0) {
countDownLabel.text = String(count--)
}
else {
timer.invalidate()
self.performSegueWithIdentifier("goestoMathTest", sender: self)
}
}
I'm trying to create a simple countdown/Up timer app for myself. So far I've figured out how to create the timers which can count up and down with a start, stop and reset buttons but I can not create a multiple timer, I'm guessing its to do with the way I'm calling the function. I'm only guessing as its my first go at it.
Variables and Labels
var timerCountUp = 0
var timerCountDown = 45
var timerRunning = false
var timer = NSTimer()
#IBOutlet weak var timerUpLabel: UILabel!
func CountingUp(){
timerCountUp += 1
timerUpLabel.text = "\(timerCountUp)"
}
#IBOutlet weak var timerDownLabel: UILabel!
func CountingDown(){
timerCountDown -= 1
timerDownLabel.text = "\(timerCountDown)"
}
Stop and Rest Buttons
#IBAction func stopButton(sender: UIButton) {
if timerRunning == true{
timer.invalidate()
timerRunning = false
}
}
#IBAction func restartButton(sender: UIButton) {
timerCountUp = 0
timerUpLabel.text = "0"
}
For my start button I have the following
#IBAction func startButton(sender: UIButton) {
if timerRunning == false{
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("CountingUp"), userInfo: nil, repeats: true)
timerRunning = true
}
If my selector is either "CountingUp" or "CountingDown" I get one of them to work, so I did a bit of searching and came up with the following which does not work
#IBAction func startButton(sender: UIButton) {
if timerRunning == false{
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("timerStarted"), userInfo: nil, repeats: true)
timerRunning = true
}
func timerStarted() {
CountingUp()
CountingDown()
}
}
Would it be possible to show me where I have gone wrong please?