use timer to countdown from what is placed in the uitextfield - swift

My swift code below should take whatever number is placed in the textfield and then count it down in by a single second. I dont know how to take what is in the textfield and get it to be counted down from. Dont worry about making sure the user places a number and not a string in the textfield.
import UIKit
class ViewController: UIViewController {
var enterTime = UITextField()
var lblTime = UILabel()
var startBTN = UIButton()
var timer = Timer()
var counter = 33
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
[enterTime,lblTime,startBTN].forEach{
$0.backgroundColor = .systemRed
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
enterTime.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 60, height: 50)
lblTime.frame = CGRect(x: view.center.x-115, y: view.center.y, width: 60, height: 50)
startBTN.frame = CGRect(x: view.center.x-115, y: view.center.y+200, width: 60, height: 50)
startBTN.addTarget(self, action: #selector(startHit), for: .touchDown)
}
#objc func startHit() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
#objc func timerAction() {
//This is where the user would take the time from uitextfield and causes it to count down
enterTime.text = counter
lblTime.text = "\(counter)"
}
}

1 ) Invalidate your timer and initiate counter with a value from enterTime textField and start your timer in startHit function.
2 ) In the timerAction function, reduce the counter value by 1 and set it in the lblTime.
You may need to modify your startHit and timerAction functions as follows.
#objc func startHit() {
timer.invalidate()
if let counterText = enterTime.text, let counterValue = Int(counterText) {
counter = counterValue
lblTime.text = String(counter)
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
}
#objc func timerAction() {
counter -= 1
lblTime.text = String(counter)
if ( counter == 0 ) {
timer.invalidate()
}
}

Related

How to make restart button appear when timer ends in Swift?

I'm trying to make a countdown timer in Swift.
When the timer is finished, a restart button appears and I want to make the timer restart.
This is My code so far.
class TimerViewController: UIViewController {
let duration: Double = 5 // duration in seconds
var timer: Timer?
var progressView: UIProgressView!
var timeElapsed: Double = 0
override func viewDidLoad() {
super.viewDidLoad()
// Create the progress view
progressView = UIProgressView(progressViewStyle: .default)
progressView.frame = CGRect(x: 20, y: 100, width: view.frame.width - 40, height: 10)
progressView.progress = 0
view.addSubview(progressView)
// Create the timer
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
}
#objc func timerFired() {
timeElapsed += 0.01
let progress = Float(timeElapsed / duration)
progressView.progress = progress
if timeElapsed >= duration {
timer?.invalidate()
timerEnded()
}
}
func timerEnded() {
// Timer has ended, do something here
// Show the restart button
print("Ended")
let restartButton = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
restartButton.setTitle("Restart", for: .normal)
restartButton.addTarget(self, action: #selector(restartTimer), for: .touchUpInside)
view.addSubview(restartButton)
}
#objc func restartTimer() {
// Restart the timer
timeElapsed = 0
progressView.progress = 0
timer?.invalidate()
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
}
}
The problem is timer Progress bar appears well, but restart button doesn't appear.
You might've already figured it out but in-case you didn't, I believe the button is there it's just that you cannot see it. Set a background colour and you should be able to see the button
Add the below statement after setting the button title in your timerEnded button
restartButton.backgroundColor = .gray
See if this helps.

Defining a #selector method when it can't access a programmatically created UILabel

If you define a UILabel programmatically, it must be done so in viewDidLoad()? But, if you were to define a #selector method that needed to set said label, it would be impossible given that the #objc selector method needs to be outside the scope of the viewDidLoad() method, where it cannot access the label. How do you get around this?
class ViewController: UIViewController {
var count = 4
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
label.center = CGPoint(x: 250, y: 430)
label.font = .systemFont(ofSize: 130)
label.textColor = UIColor.black
view.addSubview(label)
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: <#T##Selector#>, userInfo: <#T##Any?#>, repeats: <#T##Bool#>)
#objc func updateLabel() { // ERROR #objc can only be used with members of classes...
if count > 0 {
count -= 1
label.text = "\(count)"
}
}
}
}
Your mistake is that you have put the selector updateLabel inside of viewDidLoad. You should put it outside viewDidLoad so that it is a member of your class, rather than a local function.
To access the label in updateLabel, simply move the declaration of the label outside of both methods.
You should also add a timer parameter to updateLabel so that you can stop the timer when count reaches 0, rather than keeping the timer running forever.
var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
label.center = CGPoint(x: 250, y: 430)
label.font = .systemFont(ofSize: 130)
label.textColor = UIColor.black
view.addSubview(label)
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateLabel), userInfo: nil, repeats: true)
}
#objc func updateLabel(_ timer: Timer) {
if count > 0 {
count -= 1
label.text = "\(count)"
} else {
timer.invalidate()
}
}

Use Uitapgesture recognizer on multiple image views that are not declared

My swift code uses func addBox to add and append image views to the uiview controller. All I want to do is when one of the image views are tapped is for func viewClicked to be activated. Right now nothing is happening and nothing is being written into the debug area.
import UIKit
class ViewController: UIViewController {
var ht = -90
var ww = 80
var hw = 80
var arrTextFields = [UIImageView]()
var b7 = UIButton()
override func viewDidLoad() {
[b7].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
b7.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 70, height: 40)
b7.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
for view in self.arrTextFields {
view.isUserInteractionEnabled = true
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(viewClicked)))
}
}
#objc func viewClicked(_ recognizer: UITapGestureRecognizer) {
print("tap")
}
//func that adds imageview.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(ww), height: 35)
subview.backgroundColor = .purple
ht += 50
arrTextFields.append(subview)
}
}
You need to enable user interation
for view in self.arrTextFields {
view.isUserInteractionEnabled = true
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(viewClicked)))
}
#objc func viewClicked(_ recognizer: UITapGestureRecognizer) {
print("tap")
}

swift UIview removeFormSuperview

this is a test code,I want to add uiview to storyBoard ,and wait 1 second, and remove it .but the uiview doesn't appear , the code is down
var uiview1 = UIView()
uiview1.frame = CGRectMake(0, 0, 50, 50)
uiview1.backgroundColor = UIColor.blackColor()
self.view.addSubview(uiview1)
sleep(1)
uiview1.removeFromSuperview()
sleep() is not a good idea in this way. It will become totally unresponsive and block. Use NSTimer.scheduledTimerWithTimeInterval instead.
class ViewController: UIViewController {
var uiview1 = UIView()
override func viewDidLoad() {
super.viewDidLoad()
uiview1.frame = CGRectMake(0, 0, 50, 50)
uiview1.backgroundColor = UIColor.blackColor()
self.view.addSubview(uiview1)
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("dismissView"), userInfo: nil, repeats: false)
}
func dismissView() {
uiview1.removeFromSuperview()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

How to reference UILabel strong reference programmatically using Swift?

Using Swift, I have a UILabel that was created programmatically in the viewDidLoad override function:
var middleDate = UILabel(frame: CGRect(x: (screenWidth / 2) - 45, y: 0, width: 90, height: 20))
middleDate.text = "3:13:46 PM"
middleDate.font = UIFont(name: "ArialMT", size: 13)
middleDate.textAlignment = .Center
Which works great.
Then I am trying to change the text in the override function viewDidAppear.
I get Build Failed with the message Use of unresolved identifier 'middleDate'
If I use interface builder and drag and drop a UILabel on the view, then give it a strong reference it works great. Is there a way to reference a programmatically created object with a strong reference?
Or am I going about this incorrect?
This is what I have on my ViewController.swift:
I have a feeling that there is a much better and cleaner way to do this.
override func viewDidLoad() {
super.viewDidLoad()
var middleDate = UILabel(frame: CGRect(x: (screenWidth / 2) - 45, y: 0, width: 90, height: 20))
middleDate.text = "3:13:46 PM"
middleDate.font = UIFont(name: "ArialMT", size: 13)
middleDate.textAlignment = .Center
self.myTopView.addSubview(middleDate)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("getLocalTime:"),
userInfo: nil,
repeats: true)
let mainLoop = NSRunLoop.mainRunLoop()
mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode)
func getLocalTime(timer: NSTimer) {
var todaysDate:NSDate = NSDate()
var dateFormatter:NSDateFormatter = NSDateFormatter()
var centerDateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "h:mm:ss"
var DateInFormat:String = dateFormatter.stringFromDate(todaysDate)
middleDate.text = "hello"
}
}
Try this:
class ViewController: UIViewController {
var middleDate = UILabel(frame: CGRect(x: (360 / 2) - 45, y: 200, width: 90, height: 20))
override func viewDidLoad() {
super.viewDidLoad()
middleDate.text = "3:13:46 PM"
middleDate.font = UIFont(name: "ArialMT", size: 13)
middleDate.textAlignment = .Center
self.view.addSubview(middleDate)
}
override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated)
middleDate.text = "hello"
}
}
Your issue was middleDate was declared with local scope within the viewDidLoad function. In order for it to be a class variable you need to declare it at the class level. I simplified the class a little just to make it work quickly for me.