looking for some help for this, I have a timer that works after submitting a password which is great, but I then need to disable the button after the timer starts and is disabled for a period of time, (in the code I have entered a nominal 90 seconds)
however the button is not disabling.
if anybody could show me where I am going wrong that would be awesome.
import UIKit
class appiHour: UIViewController {
var timer = Timer()
var counter = 60
var password_Text: UITextField?
func enableButton() {
self.timerStartButton.isEnabled = true
}
#IBOutlet weak var timerLabel: 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 timerStartButton(_ sender: Any) {
var password_Text: UITextField?
let alertController = UIAlertController(title: "To start your own 2 Cocktails for £10 APPi Hour", message: "get a memeber of the team to enter the password, but use it wisely, as you can only use it once per day, with remember great power comes great responsability", preferredStyle: UIAlertControllerStyle.alert)
let tickoff_action = UIAlertAction(title: "let the APPiness commence", style: UIAlertActionStyle.default) {
action -> Void in
self.timerStartButton.isEnabled = false
Timer.scheduledTimer(timeInterval: 90, target: self, selector: #selector(appiHour.enableButton), userInfo: nil, repeats: false)
if let password = password_Text?.text{
print("password = \(password)")
if password == "baruba151" {
self.counter = 60
self.timerLabel.text = String(self.counter)
self.timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(appiHour.updateCounter), userInfo: nil, repeats: true)
}
} else {
print("No password entered")
}
}
alertController.addTextField { (txtpassword) -> Void in
password_Text = txtpassword
password_Text!.isSecureTextEntry = true
password_Text!.placeholder = ""
}
alertController.addAction(tickoff_action)
self.present(alertController, animated: true, completion: nil)
}
#IBOutlet weak var timerStartButton: UIButton!
func updateCounter() {
counter -= 1
timerLabel.text = String(counter)
if counter == 0{
timer.invalidate()
counter = 0
}
}
}
As a secondary question is it possible to run the timer while the app is in the background? i know apple frowns on this aside for Sat Nav, Music apps etc. But is there a method in which the timer is held and a notification is sent locally letting the user know the timer has ended?
thanks in advance.
I suspect that your action may not be hooked up to your button. I just tried the following code with no issues. The button gets disabled, and then enabled 5 seconds later:
class ViewController: UIViewController {
#IBOutlet weak var myButton: UIButton!
#IBAction func ButtonPressed(_ sender: Any) {
myButton.isEnabled = false
Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(myTimerTick), userInfo: nil, repeats: false)
}
func myTimerTick() {
myButton.isEnabled = true
}
}
So make sure your outlets and actions are hooked up to the button correctly. If you right click on your button, you should see the dots filled in next to the outlet and action. You should see similarly filled in dots in your code.
You can further verify it is hooked up by placing a breakpoint in your "timerStartButton" method and making sure that breakpoint is hit.
Edit to further clarify: You need to connect your code to your Interface build objects. See this article from Apple for a complete tutorial on how to do that.
I'm not 100% sure if this is what you mean. But this would at least satisfy the first part of your request: disable a button whilst a timer is running, and re-enable it once the timer stops.
#IBOutlet weak var myButton: UIButton!
#IBOutlet weak var timerCount: UILabel!
#IBAction func buttonPressed(_ sender: UIButton) {
var count = 0
sender.isEnabled = false
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [unowned self] timer in
count += 1
if count == 5 {
count = 0
sender.isEnabled = true
timer.invalidate()
}
self.timerCount.text = "\(count)"
}
}
Here's a couple of screenshots of what you get.
It's enabled when the user starts off, disabled whilst the count is going then reverts back to its original state with counter at 0 and button enabled. Is that what you're going for?
As far as your second question, what do you mean by
the timer is held
Do you want the timer to keep running whilst the app is in the background, then update the user once the timer has elapsed? If so, take a look at this answer which should point you in the right direction: Continue countdown timer when app is running in background/suspended
Related
Here is the code that I am using, at the bottom of the code is my timer it is a timer counting up and once it hits 60 minutes I would like for a button to turn red.
import UIKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnPressed1(_ sender: UIButton) {
sender.backgroundColor = sender.backgroundColor == UIColor.red ? UIColor.black : UIColor.red
}
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var progressBar1: UIProgressView!
let start = 5
var timer = Timer()
var player: AVAudioPlayer!
var totalTime = 0
var secondsPassed = 0
#IBAction func startButtonPressed(_ sender: UIButton) {
let startB = sender.titleLabel?.text
totalTime = start
progressBar1.progress = 0.0
secondsPassed = 0
titleLabel.text = "coffee timer"
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
#objc func updateTimer() {
if secondsPassed < totalTime {
secondsPassed += 1
progressBar1.progress = Float(secondsPassed) / Float(totalTime)
print(Float(secondsPassed) / Float(totalTime))
} else {
timer.invalidate()
titleLabel.text = "check coffee"
let url = Bundle.main.url(forResource: "alarm_sound", withExtension: "mp3")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
}
}
I need the button to turn the color red after my timer ends and if possible when the button is pressed have the color turn back to black.
You could add an IBOutlet to the button, and then use that outlet to update the button in your updateTimer routine.
An alternative to adding an IBOutlet to the button is to pass the button as the userInfo: parameter of the Timer.
You can pass anything you want as the userInfo: and right now you're just passing nil. If you change nil to sender, then the button will be passed along to the Timer.
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self,
selector: #selector(updateTimer), userInfo: sender,
repeats: true)
Then, add the Timer parameter to updateTimer:
#objc func updateTimer(t: Timer) {
if let button = t.userInfo as? UIButton {
button.backgroundColor = .red
}
}
Making use of userInfo makes even better sense if you have multiple buttons that share the same updateTimer code. By creating a structure to hold the secondsPassed and button and passing that structure as userInfo:, you could have multiple buttons using multiple timers at the same time and each Timer would know which button it was assigned to.
I am trying to make words in an array show up one at a time on a label, but with my code, the last word in the array shows up. What I want is for my label to display Hello [wait] (a certain amount of time preferably adjustable at some point) World [wait] Testing [wait] Array
Here's my code:
import UIKit
// Variables
let stringOfWords = "Hello World. Say Hello. Test Number One."
let stringOfWordsArray = stringOfWords.components(separatedBy: " ")
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var labelWords: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for word in stringOfWordsArray {
labelWords.text=(word)
}
}
}
I want to be able to have an adjuster for how fast the words show up and a start and stop button. If anyone can help me with that main part that would be great.
The simplest approach is to use Timer so you will be able to call start/stop it and adjust time (2 seconds in example below):
var timer: Timer?
var wordIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(update), userInfo: nil, repeats: true)
}
#objc func update() {
label.text = stringOfWordsArray[wordIndex]
if wordIndex < (stringOfWordsArray.count - 1) {
wordIndex += 1
}
else {
// start again ...
wordIndex = 0
}
}
#IBAction func startAction(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(update), userInfo: nil, repeats: true)
}
#IBAction func stopAction(_ sender: Any) {
// remember to invalidate and nil it when you leave view
timer?.invalidate()
timer = nil;
}
I'm trying to add a navigation bar refresh button to update my table view content that coming from JSON and beside that i want my table view keep updating automatically every 5 minutes if the user hasn't pressed the refresh button and changing the button to be an Activity indicator to let the user that is been updating when the table view updating the data
my refresh button IBAction code :
#IBAction func refreshButton(_ sender: Any) {
self.getCoinData()
self.coinTableView.reloadData()
}
Swift 4+
Create Timer & on completion of webservice show the reload icon
class ViewController: UIViewController {
var timer: Timer!
var refreshBarButtonActivityIndicator: UIBarButtonItem!
var refreshBarButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
barItemSetUp()
}
func barItemSetUp() {
///SettingReloadButton
let image = UIImage(named: "refresh-25")?.withRenderingMode(.alwaysOriginal)
refreshBarButton = UIBarButtonItem(image: image, style: .plain, target: self, action: nil)
///Setting activity Indicator
let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
refreshBarButtonActivityIndicator = UIBarButtonItem(customView: activityIndicator)
activityIndicator.startAnimating()
toogleIndicator()
}
deinit {
timer?.invalidate()
}
func toogleIndicator() {
// 5 minutes = 300 seconds //write here 300
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(refreshNow), userInfo: nil, repeats: true)
}
#objc func refreshNow() {
//here i am creating delay for sample purpose
//here write your webservice code on completion of webservice change bar button item
self.navigationItem.rightBarButtonItem = refreshBarButtonActivityIndicator
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.navigationItem.rightBarButtonItem = self.refreshBarButton
}
}
}
Output:-
First add the timer which is refresh data every 5 minutes. At timer, you add the web service.
var timer = Timer()
func runTimer(){
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(self.updateTimer)), userInfo: nil, repeats: true)
}
func updateTimer() {
self.getCoinData()
self.coinTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool){
runTimer()
}
To reload your UITableView after every 5 minutes, you need to schedule a Timer that executes a block of code every 5 minutes, i.e.
var timer: Timer?
override func viewDidLoad()
{
super.viewDidLoad()
self.timer = Timer.scheduledTimer(withTimeInterval: 300, repeats: true, block: {[weak self] (tt) in
self?.getCoinData()
self?.coinTableView.reloadData()
})
timer?.fire()
}
deinit
{
timer?.invalidate()
}
You can change the time interval according to your requirement. You need to give the time interval in seconds.
This question already has answers here:
Detect iOS app entering background
(7 answers)
Closed 5 years ago.
I have a page on my app that runs a counter when the button is pressed. It stops running when I go to another page or when the app is completely terminated via double tapping home and swiping it away. That's fine with me and exactly what i want it to do. I would also like the counter to stop when i just press the home button even if the app is running still, I want the counter to stop. Ill post my counter below.
class Miner: UIViewController {
//Start
#IBOutlet weak var startMining: UIButton!
//Coin Label
#IBOutlet weak var coinLabel: UILabel!
//Counter
var count:Int {
get {
return UserDefaults.standard.integer(forKey: "count")
}
set {
UserDefaults.standard.set(newValue, forKey: "count")
coinLabel.text = "Coins: 0. \(newValue)"
}
}
var counting:Bool = false
var timer:Timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
}
#objc func counter() -> Void {
count += 1
coinLabel.text = "Coins: 0." + String(count)
walletLabel.text = "Wallet: 0." + String(count)
}
#IBAction func startMining(_ sender: Any) {
if counting {
// Stop Counting
startMining.setTitle("Start", for: .normal)
timer.invalidate()
counting = false
} else if !counting {
// Start Counting
startMining.setTitle("Stop", for: .normal)
// Start timer
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector (counter), userInfo: nil, repeats: true)
counting = true
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
}
func appDidEnterBackground() {
// stop counter
}
I've implemented a count-down timer that will automatically start my application if the user doesn't select any options. When the timer hits zero, I invalidate it and fire performSegueWithIdentifier, which segues me to my desired view.
At that point all is fine... well, sort of. I do notice that my view fires twice, but its fine after that. At this point, if I navigate away from that view, then back again, my segue fires and the view loads over and over until I stop my app.
my output window shows:
2015-05-13 21:20:26.880 Web App Browser[43407:7957566] Unbalanced
calls to begin/end appearance transitions for
. 2015-05-13
21:20:28.825 Web App Browser[43407:7957566] Unbalanced calls to
begin/end appearance transitions for .
Here's my view controller:
class StartViewController: UIViewController {
var countDown = Bool()
var timer = NSTimer()
var count = 5
#IBOutlet weak var countdownLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
countDown = AppDelegate().userDefaults.valueForKey("Auto Start") as! Bool
if countDown == true {
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
} else {
countdownLabel.text = ""
}
}
func update() {
countdownLabel.text = "\(count)"
if count == 0 {
timer.invalidate()
self.performSegueWithIdentifier("toWeb", sender: nil)
} else {
count--
}
}
}
my storyboard:
In the image below, you see my selected segue, which takes the user from the start screen into a navigation controller that has an embedded viewController. You'll note that I've added my Identifier as "toWeb".
My Question:
What would cause my segue to infinitely loop?
Not sure if this is directly related to your issue, but you are declaring timer twice, once locally and once at class scope.
var countDown = Bool()
var timer = NSTimer()
var count = 5
#IBOutlet weak var countdownLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
countDown = AppDelegate().userDefaults.valueForKey("Auto Start") as! Bool
if countDown == true {
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
} else {
countdownLabel.text = ""
}
}
you see the var timer = NSTimer() creates a timer at class scope
var timer = NSTimer.scheduleTimerWithTimeInterval... creates a new timer in the scope of viewDidLoad. I assume that should just be timer = NSTimer.scheduleTimer...
I suppose this was pretty obvious, but my update was getting called every second... because i told it to. And I put my performSegueWithIdentifier inside it. So, easy fix.
var segueFlag = false
func update() {
countdownLabel.text = "\(count)"
if count == 0 {
timer.invalidate()
if segueFlag == false {
self.performSegueWithIdentifier("toWeb", sender: nil)
segueFlag = true
}
} else {
count--
}
}