Let's say I have a class Timer that works as a timer.
I want every other class that can act like a timer to have an attribute of type Timer.
The problem is: the Timer class uses a NSTimer attribute and I don't know how to associate functions from outside Timer in it.
For example: Class A has attribute B, which is Timer. How can scheduledTimerWithTimerInterval call some function of A?
Here is timer:
import UIKit
class Timer{
var interval: NSTimeInterval!
var counting: Bool = false
var numberOfTouches: Int = 0
private var timer: NSTimer = NSTimer()
init(interval: CGFloat){
self.interval = NSTimeInterval(interval)
self.counting = false
}
func Start(function: String) {
if(self.counting){
self.numberOfTouches += 1
self.timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(self.interval, target: self, selector: Selector(function), userInfo: nil, repeats: false)
}
else{
self.counting = true
self.numberOfTouches = 1
}
}
func Stop(){
if(!self.counting){
self.counting = false
}
}
}
here is the ViewController:
import UIKit
class ViewController: UIViewController {
var timer: Timer = Timer(interval: 1.0)
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func Trigger(sender: AnyObject) {
//yes, this doesn't call t() from the ViewController
timer.Start("self.t")
}
func t(){
label.text = String(timer.numberOfTouches)
}
#IBOutlet weak var label: UILabel!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Finally, what this timer tries to do is:
when I press the button, it starts counting and set the number of touches to 1;
if I press it again, less than 1 second after the touch before, it restart the 1 second timer and increases the touch by 1;
after 1 second without any touch, it should call t() from the ViewController to set the label to the last number of touches.
What approach should I use to fix this?
Thank you!
PS: in the beginning, it was Selector("Stop")
It's not "self.t", you supply the object as the target. The selector is something like "ViewController.t" or "t". You need to change Start to take a target object as well.
Move to Xcode 7.3.1 and use the new selector syntax if you can -- it will be type-checked.
Related
I have a watchkit timer,
However, I have no idea how to perform an action like a notification or segue when the timer ends.
Any ideas?
#IBOutlet var sceneTimer: WKInterfaceTimer!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
sceneTimer.setDate(NSDate(timeIntervalSinceNow :21) as Date)
}
override func willActivate() {
super.willActivate()
sceneTimer.start()
}
override func didDeactivate() {
super.didDeactivate()
}
Yes I am new to this whole thing so its not a ground-breaking code, feel free to correct.
Someone could certainly improve upon this I'm sure. But I built a little watchOS App with a Start Button, a timer and a label. Hook up your WKInterfaceTimer, WKInterfaceLabel and Button as appropriate and this code should work. You can also download the project from GitHub.
var theTimer = Timer()
var backgroundTimer = TimeInterval(15)
#IBOutlet var appleTimer: WKInterfaceTimer!
#IBOutlet var label: WKInterfaceLabel!
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
appleTimer.setDate(Date(timeIntervalSinceNow: 15))
label.setText("")
}
#IBAction func startButton() {
let startTime = Date(timeIntervalSinceNow: 15)
appleTimer.setDate(startTime)
appleTimer.start()
// This will call timerCountDown() once per second until conditions are met.
theTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerCountDown), userInfo: nil, repeats: true)
}
func timerCountDown() {
backgroundTimer -= 1.0
print(backgroundTimer)
if backgroundTimer == 0 {
theTimer.invalidate()
appleTimer.stop()
// You could call an Alert Action here.
label.setText("Timer Done!")
}
}
WKInterfaceTimer is just a label that can be used to display a countdown. It has no associated function that is called by the system once the countdown reaches zero. You need to configure a Timer object with the same target date if you need to know when the countdown reaches 0.
I have a number of initial settings in the viewDidLoad:
countDownLabel.alpha = 1
countDownLabel.text = "01:30"
swipeLeft.alpha = 0
swipeRight.alpha = 0
pressPlayToStartOr.alpha = 0
swipeToChangeTheSeq.alpha = 0
countDownPauseLbl.alpha = 0
I have an NSTimer (I've put func update () of the timer inside inside viewDidLoad as well, while it is triggered by a UIButton outside viewDidLoad). The timer continues running when I segue from the UI View Controller. When I segue back to the Timer View Controller, I can hear the sound of the timer running, but the Timer View Controller is refreshed to it's initial state and you can run the timer again so that they overlap. The programmatic segue after the timer finishes doesn't work in this case. I understand that I may have used the wrong approach, but hope it can be fixed. How can I make the label update, regardless of where I'am at in the app.
The effect:
In SingletonTimer.swift:
//
// SingletonTimer.swift
// testSwiftUITextField
//
// Created by leo on 2016/12/17.
// Copyright © 2016年 leo. All rights reserved.
//
import UIKit
class SingletonTimer: NSObject {
private static let sharedInstance = SingletonTimer()
class var sharedSingletonTimer:SingletonTimer {
return sharedInstance
}
var timeCount:Int = 100
func countDown() {
timeCount -= 1
timer_closure(timeCount)
}
lazy var timer:Timer = {
var timer:Timer
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { (timer) in
self.countDown()
})
} else {
// Fallback on earlier versions
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countDown), userInfo: nil, repeats: true)
}
return timer
}()
var timer_closure:(Int)->Void = { (count) in
}
}
In ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
In ViewController2.swift:
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var label: UILabel!
var timer:Timer? = nil
override func viewDidLoad() {
super.viewDidLoad()
timer = SingletonTimer.sharedSingletonTimer.timer
SingletonTimer.sharedSingletonTimer.timer_closure = { (timeCount) in
print("\(timeCount)")
self.label.text = "\(timeCount)s !"
}
if timer != nil {
timer?.fire()
}
}
}
I'm having trouble compiling this code in Swift successfully. Its a program for stopwatch. Two labels(start and stop) and a textfield as the output. It says its a delegate problem and highlights this in red:
class AppDelegate: UIResponder, UIApplicationDelegate
My code for the project is as follows:
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
var counter = 1
#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.
}
func updateCounter()
{
counter += 1
Label.text = String(counter)
}
#IBAction func Start(sender: AnyObject)
{
counter = 0
Label.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector ("updateCounter"), userInfo: nil, repeats: true)
}
#IBAction func Stop(sender: AnyObject)
{
timer.invalidate()
}
}
Very common problem, here's what you have to do:
Go through every outlet on your storyboard and delete it.
Reconnect every function in your ViewController to the outlets.
The problem, I believe, is that you have changed the name of an outlet in your code, and when the storyboard looks for that outlet it crashes your app. Make sure that when you rename your outlets, you reconnect it too!
This is my first post so I hope this is a valid question. I've searched the forums for an answer to this with no luck. Below is my code for a stopwatch app. Problem I am having is when the play button is clicked multiple times it is ticking multiple seconds at a time. How do I safely stop this from happening?
ViewController
import UIKit
class ViewController: UIViewController {
// MARK: Properties
#IBOutlet weak var timerLabel: UILabel!
var timer = NSTimer()
var time = 0
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: Functions
func increaseTimer() {
time++
let formattedTime = String(format:"%02d:%02d", (time/60), time%60)
timerLabel.text = "\(formattedTime)"
}
// MARK: Actions
#IBAction func btnPlay(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self,
selector: Selector("increaseTimer"), userInfo: nil, repeats: true)
}
#IBAction func btnStop(sender: AnyObject) {
timer.invalidate()
}
#IBAction func btnReset(sender: AnyObject) {
timer.invalidate()
time = 0
timerLabel.text = "00:00"
}
}
EDIT: SOVED http://imgur.com/mqw1Xnp
Make your button into a start/stop button. Use a boolean instance variable to keep track of whether the timer is running or not. If it is, stop it. If it's not, start it.
Alternately, make the code that starts the timer set button.disabled = true
How do i stop my timer from running? Not like a pause, but a stop.
import UIKit
class LastManStandingViewController: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var timeTextbox: UITextField!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var stopButton: UIButton!
var myCounter = 0
var myTimer : NSTimer = NSTimer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timeLabel.text = String(myCounter)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func startTimer(){
myTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTimer"), userInfo: nil, repeats: true)
println("func startTimer")
}
func stopTimer(){
myTimer.invalidate()
myCounter = 0
timeLabel.text = String(myCounter)
println("func stopTimer")
}
func updateTimer(){
timeLabel.text = String(myCounter++)
println("func updateTimer")
}
#IBAction func startButton(sender: AnyObject) {
startTimer()
}
#IBAction func stopButton(sender: AnyObject) {
stopTimer()
}
}
I can start the timer, but when i press the Stop button, it reset itself, and starts counting again. It doesn't stop.
Made it work. Something was buggy with my project! Fixed it by removing the button and re-adding them. Looks like i had a duplicate or something.
You don't have to use Selector:
#IBAction func startButton(sender: AnyObject) {
myTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTimer:", userInfo: nil, repeats: true)
}
Also, the timer passes itself to the selected method, so you can invalidate it inside the method if you need:
func updateTimer(timer: NSTimer) {
timeLabel.text = String(Counter++)
timer.invalidate()
}
Or if the timer is an instance variable:
myTimer.invalidate()
myTimer = nil
It's a good thing to nil the instance variable timer after having invalidated it, it avoids further confusion if you need to create another timer with the same variable. Also, method names and variables should begin with a lowercase letter.
Screenshot to show the timer invalidated and set to nil.
Update for Swift 2.2+
See https://stackoverflow.com/a/36160191/2227743 for the new #selector syntax replacing Selector().
you can use this when some condition is met and you want to stop timer:
Timer.invalidate()
Here is simple example :
func UpdateTimer(){
timeLabel.text = String(Counter++)
if timeLabel.text == String("5") {
Timer.invalidate()
}
}
this will stop timer.
You can modify it as per your need.
As pre Swift 2.2
let printTimer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(printDescription), userInfo: nil, repeats: true)
func printDescription() {
print("Print timer will print every after 2.0 seconds")
}
Print timer will print every after 2.0 seconds