How to make a Label disappear when button is pushed? - swift

I am currently working on a very basic quiz app.
The user will have the option of 4 choices.
If the correct button is pressed, the hidden label (LabelEnd) will show "Correct" and automatically go to the next randomized question.
If they push the wrong button, the hidden label will then read "Wrong" and stay on the same question.
My question is: how do I make it so that the label is hidden again after 1 second, regardless if it is correct or wrong?
func Hide() {
LabelEnd.hidden = true
}
func UnHide(){
LabelEnd.hidden = false
}
#IBAction func Button1Action(sender: AnyObject) {
UnHide()
if(CorrectAnswer == "1"){
LabelEnd.text = "Correct!"
RandomQuestions()
} else {
LabelEnd.text = "Wrong"
}
}

You can use the UIView animate method with duration where you can set your interval time.
Like this:
UIView.animateWithDuration(0.1, animations: { () -> Void in
LabelEnd.hidden = false
})

You can hide your label after 1 second this way:
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
self.LabelEnd.hidden = true
})
And you can change time as per your need.
And you can use it this way:
func Hide() {
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
self.LabelEnd.hidden = true
})
}
#IBAction func Button1Action(sender: AnyObject) {
UnHide()
if(CorrectAnswer == "1"){
LabelEnd.text = "Correct!"
Hide()
}
else{
LabelEnd.text = "Wrong"
Hide()
}
}
One more way to do that is you can use timer for that as shown in below code:
var timer = NSTimer()
func Hide() {
LabelEnd.hidden = true
timer.invalidate() //You can remove timer here.
}
func UnHide(){
LabelEnd.hidden = false
}
#IBAction func Button1Action(sender: AnyObject) {
UnHide()
if(CorrectAnswer == "1"){
LabelEnd.text = "Correct!"
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Hide"), userInfo: nil, repeats: false)
}
else{
LabelEnd.text = "Wrong"
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Hide"), userInfo: nil, repeats: false)
}
}

Related

background run timer swift

I want the timer to run even when I close the application. I want it to work in the background counter. the timer goes back one second when I run it.(counter) How can I do that?
class TimerViewController: UIViewController {
var selectedDay: String?
var seconds =
var timer = Timer()
#IBAction func start(_ sender: AnyObject) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(TimerViewController.counter), userInfo: nil, repeats: true)
sliderOutlet.isHidden = true
startOutlet.isHidden = true
}
#objc func counter() {
seconds -= 1
favoriteDayTextField.text = String(seconds) + " Seconds"
var bgTask = UIBackgroundTaskIdentifier(rawValue: seconds)
bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
UIApplication.shared.endBackgroundTask(bgTask)
})
if (seconds == 0) {
timer.invalidate()
if self.button.isOn {
updateState()
} else {
updateState1()
}
}
}
}
I am not clear what you want to achieve. Suppose you want to update the label after the timer has started each 1 second. Then one approach will be:-
Start the timer in view did load if the duration is remaining.
Register for applicationWillTerminate
In application will terminate save the passed duration and terminated time to calculate remaining time in next launch.
var remainingDuration: TimeInterval!
override func viewDidLoad() {
super.viewDidLoad()
let remainingDurationFromLastLaunch = UserDefaults.standard.object(forKey: "duration") as? TimeInterval ?? 0
let lastTerminatedTime = UserDefaults.standard.object(forKey: "lastTerminatedDate") as? Date ?? Date()
if Date().timeInterval(since: lastTerminatedTime) > remainingDurationFromLastLaunch {
remainingDuration = remainingDurationFromLastLaunch - Date().timeInterval(since: lastTerminatedTime)
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(TimerViewController.counter), userInfo: nil, repeats: true)
NotificationCenter.default.addObserver(self, selector: #selector(TimerViewController.applicationWillTerminate), name: NSNotification.Name.UIApplicationWillTerminate, object: nil)
} else { //Duration is passed....Do whatever you want
}
}
#objc func counter() {
remainingDuration -= 1
if remainingDuration == 0 { //Duration is passed....Do whatever you want
timer.invalidate()
timer = nil
} else {
favoriteDayTextField.text = String(remainingDuration) + " Seconds"
}
}
#objc func applicationWillTerminate() {
if timer != nil {
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
UserDefaults.standard.set(remainingDuration, forKey: "duration")
UserDefaults.standard.set(Date(), forKey: "lastTerminatedDate")
}
self?.endBackgroundTask()
}
}
func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
The only way for your iOS application to perform some action even while it is in the background is to use Background Modes .
However you cannot perform anything and everything while your
application is in background
There are certain limitations to the type of tasks that you can perform . I have attached a really good article for your reference
Background Modes Tutorial
However, I am not sure if you can initiate and continue a timer sort of functionality while your application is in background
Though, keep in mind , once your application is closed (i.e. by double tapping the home button and swiping the application window up to close it completely) , not even Background modes work at that point because the user does not want to run your app anymore, even in the background

Timer counts instantly instead of respecting interval

Im trying to make a countdown timer. everything works fine except that my timer does not count at regular intervals (1sec); instead it counts all the way down instantly giving me 0 every time. did a lot of search without luck. All examples I could find show similar timeInterval parameter.
var timer = Timer()
var remainingTime = 120
#objc func timerCount () {
if remainingTime > 0 {
while remainingTime > 0 {
remainingTime -= 1
timerLabel.text = String(remainingTime)
print(remainingTime)
}
} else {
timer.invalidate()
}
}
#IBAction func pauseButton(_ sender: Any) {
timer.invalidate()
}
#IBAction func playButton(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.timerCount), userInfo: nil, repeats: true)
}
The reason your code is not working is that you have put an unnecessary while loop in your timerCount() method. You don't need to do this. Your timer will fire this method after each time interval. At very first call this while loop make your remainingTime to 0. This is why you are instantly getting 0 every time.
You just need to remove that while loop.
Can You try like this
var timer = Timer()
var remainingTime = 120
#objc func timerCount () {
let date = NSDate()
let nowdate = UserDefaults.standard.object(forKey: "NowDate") as! Date
let miniute = nowdate.timeIntervalSince(date as Date)
print(Int(miniute))
if (Int(miniute) == 0) {
timer.invalidate()
UserDefaults.standard.removeObject(forKey: "NowDate")
} else {
timerLabel.text = String(Int(miniute))
}
}
#IBAction func pauseButton(_ sender: Any) {
timer.invalidate()
UserDefaults.standard.removeObject(forKey: "NowDate")
}
#IBAction func playButton(_ sender: Any) {
let CurrentDate = NSDate()
let NowDate = CurrentDate.addingTimeInterval(TimeInterval(remainingTime))
UserDefaults.standard.set(NowDate, forKey: "NowDate")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.timerCount), userInfo: nil, repeats: true)
}

How to stop backgroundUpdateTask?

Here is code which I execute in background when user close the app, but it is weird behavior , after endBackgroundUpdateTask() method is executed , DispatchQueue still doesn't stops...
I steel continuos get notification.
What am I doing wrong?
you can try to take this snipped of code and try for yourself, it is really weird
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
func beginBackgroundUpdateTask() {
print("beginBackgroundUpdateTask")
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
print("endBackgroundUpdateTask")
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
}
func doBackgroundTask() {
print("Strart")
DispatchQueue.global().async {
self.beginBackgroundUpdateTask()
// Do something with the result.
let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(AppDelegate.displayAlert), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
// End the background task.
self.endBackgroundUpdateTask()
}
print("Finish")
}
func displayAlert() {
print("displayAlert")
let note = UILocalNotification()
note.alertBody = "As a test I'm hoping this will run in the background every X number of seconds..."
note.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(note)
}
func applicationDidEnterBackground(_ application: UIApplication) {
log.debug("applicationDidEnterBackground")
self.doBackgroundTask()
}
edit
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
var timerr: Timer?
func beginBackgroundUpdateTask() {
appDeligate.log.debug("beginBackgroundUpdateTask")
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
appDeligate.log.debug("endBackgroundUpdateTask")
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
timerr = nil
}
func doBackgroundTask() {
print("Strart")
DispatchQueue.global().async {
self.beginBackgroundUpdateTask()
// Do something with the result.
self.timerr = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(TestViewController.displayAlert), userInfo: nil, repeats: true)
RunLoop.current.add(self.timerr!, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
// End the background task.
self.endBackgroundUpdateTask()
}
print("Finish")
}
func displayAlert() {
print("displayAlert")
let note = UILocalNotification()
note.alertBody = "As a test I'm hoping this will run in the background every X number of seconds..."
note.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(note)
}
Really issue was with Timer, I was needed put this line
timerr?.invalidate()
here
func endBackgroundUpdateTask() {
appDeligate.log.debug("endBackgroundUpdateTask")
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
timerr?.invalidate()
}
But anyway it is little bit weird , because I thought if I was stopping backgroundUpdate() all tasks inside had to invalidate and purge automatically, but no.
Thanks #matt

How can I access viewcontroller's NSTimer from TabBarController in Swift

I'm new on Swift. I have a Tab Bar Controller in my ios app. I am starting NSTimer in my first tab which name is as HomePageViewController as below :
override func viewDidLoad() {
super.viewDidLoad(){
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTimer", userInfo: nil, repeats: true)
}
func stopTimer(){
print("stop timer")
self.timer?.invalidate()
self.timer=nil
}
func reStartTimer(){
print("restart timer")
timer?.invalidate()
timer=nil
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTimer", userInfo: nil, repeats: true)
}
My didSelectItem method in TabBarController.swift is :
override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
if item == (self.tabBar.items![0]){
//necessary operation
}
else {
homePageVC.stopTimer()
}
but timer doesn't stop. How can I stop timer from TabBarViewController ?
You should invalidate your timer. See the documentation here.
if item == (self.tabBar.items![0]){
//necessary operation
} else {
homePageVC.invalidate()
}
ok I fixed problem :
override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
let homePageVC = self.viewControllers![0] as! HomePageViewController
if item == (self.tabBar.items![0]){
if (lastSelectedTabItem==0){
}
else{
homePageVC.reStartTimer()
}
}
else {
homePageVC.stopTimer()
}
if(item.title=="Tab1"){
lastSelectedTabItem=0
}
else if(item.title=="Tab2"){
lastSelectedTabItem=1
}
else if(item.title=="Tab3"){
lastSelectedTabItem=2
}
else {
lastSelectedTabItem=3
}
}

Timer.fire() not working after invalidating in Swift

After using
#IBAction func pauseButton(sender: AnyObject) {
if isPaused == false {
timer.invalidate()
isPaused = true
displayLabel.text = "\(count)"
println("App is paused equals \(isPaused)")
} else if isPaused == true {
var isPaused = false
timer.fire()
// timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTime"), userInfo: nil, repeats: true)
}
}
to pause the app, i'd like to hit pause again, in which case, the timer will continue to count from where it left off.
Additionally, when i press pause/play too many times, multiple instances of the timer occur which will cause the timer to increase a few times per second.
Please help!
//
// ViewController.swift
// Navigation Bars
//
// Created by Alex Ngounou on 8/27/15.
// Copyright (c) 2015 Alex Ngounou. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
var count = 0
var isPaused = false
func updateTime() {
switch count {
case 0, 1:
count++
println( "\(count) second.")
displayLabel.text = "\(count)"
case 2:
count++
println("\(count) seconds.")
displayLabel.text = "\(count)"
default:
count++
println("\(count) seconds.")
displayLabel.text = "\(count)"
}
}
**strong text**#IBAction func playButton(sender: AnyObject) {
var isPaused = false
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTime"), userInfo: nil, repeats: true)
}
#IBAction func stopButton(sender: AnyObject) {
timer.invalidate()
count = 0
displayLabel.text = "0"
}
// if it's currently paused, pressing on the pause button again should restart the counter from where it originally left off.
#IBAction func pauseButton(sender: AnyObject) {
if isPaused == false {
timer.invalidate()
isPaused = true
displayLabel.text = "\(count)"
println("App is paused equals \(isPaused)")
} else if isPaused == true {
var isPaused = false
timer.fire()
// timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTime"), userInfo: nil, repeats: true)
}
}
#IBAction func resetButton(sender: AnyObject) {
timer.invalidate()
count = 0
displayLabel.text = ""
}
#IBOutlet weak var displayLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateTime"), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
From: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/
Once invalidated, timer objects cannot be reused.
So essentially an NSTimer will do nothing at all once invalidated. Your timer property must be assigned to a newly constructed NSTimer object after that point to get it to fire again. If your invalidation bookkeeping is accurate, there is no "buildup" problem of multiple timers.
Probably the easiest method to your actual problem, though, is logical filtering. That is, keep the NSTimer object around indefinitely and let it fire continually. When the stored property isPaused is true, you ignore timer events (by returning immediately from the processing function), otherwise you process them.
a "lazier" approach can be otherwise useful:
class ViewController: UIViewController {
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
startTimer()
}
final func killTimer(){
self.timer?.invalidate()
self.timer = nil
}
final private func startTimer() {
// make it re-entrant:
// if timer is running, kill it and start from scratch
self.killTimer()
let fire = Date().addingTimeInterval(1)
let deltaT : TimeInterval = 1.0
self.timer = Timer(fire: fire, interval: deltaT, repeats: true, block: { (t: Timer) in
print("hello")
})
RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
}
Declare your timer as 'weak var' like this:
weak var timer: Timer?