How to make ios app stop when home button pressed [duplicate] - ios

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
}

Related

How to change the collor of a button once timer runs out?

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.

How to make an array show up on a label one by one

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;
}

Disable timer button after validation Swift - Not working

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

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.

What would cause my segue to infinitely loop?

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--
}
}

Resources