Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Hey so I'm new to coding and I placed a button on my View Controller (Drag and drop). The button is not responding to touch or anything and appears 'static.' I'm tired and exhausted. Someone help? Thank you so much!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lblMadeToday: UILabel!
#IBOutlet weak var Cents: UILabel!
var timer = NSTimer()
var hourlyWage : CGFloat = CGFloat (hourlyPrice)
var timeTo1 : CGFloat = 0
var time : Float = 0
var earnt : CGFloat = 0
var madeToday : CGFloat = 0
#IBAction func btnClick(sender: AnyObject) {
}
func tick() {
earnt = CGFloat (time)/timeTo1
lbl1.text = NSString(format: "%.2f", earnt) as String
if (earnt >= 1) {
time = 0
madeToday++
lblMadeToday.text = madeToday.description
}
time++
}
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
timeTo1 = CGFloat (360000)/hourlyWage;
println("view Loaded :)")
NSNotificationCenter.defaultCenter().addObserver(self, selector:"doYourStuff", name:
UIApplicationWillEnterForegroundNotification, object: nil)
}
func doYourStuff(){
var nowHour = NSCalendar.currentCalendar().component(.CalendarUnitHour, fromDate: NSDate())
var nowMinute = NSCalendar.currentCalendar().component(.CalendarUnitMinute, fromDate: NSDate())
var nowSecond = NSCalendar.currentCalendar().component(.CalendarUnitSecond, fromDate: NSDate())
var time1 = (nowHour - globalHour) * 60
var time2 = (nowMinute - globalMinute)
var time3 : CGFloat = (CGFloat(nowSecond)-CGFloat(globalSecond))/60
var timeInMinutesGone : CGFloat = CGFloat(time1) + CGFloat(time2) + CGFloat(time3)
println (timeInMinutesGone)
madeToday = (timeInMinutesGone / 60) * (CGFloat(hourlyWage))
var ef : Int = Int(madeToday)
lblMadeToday.text = String(ef)
}
#IBAction func btnPress(sender: AnyObject) {
println("hello")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your NSTimer is being executed in the UI thread every 0.01 seconds. This could be detrimental for your app. It's likely that if you execute NSTimer in a background thread, your button will work as expected.
One way to add your NSTimer to background could be:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
NSRunLoop.currentRunLoop().run()
})
Related
For some reason the stopwatch looks to be alright, but when compared to the real deal it goes way too fast. I don't understand what I should do. Is it the timeInterval that I should change? I would like it to show millisecond, second and minutes, but everything I try just makes it worse.. Thank you
import UIKit
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var minutes: UILabel!
#IBOutlet weak var seconds: UILabel!
#IBOutlet weak var milliSecondsLabel: UILabel!
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var pauseButton: UIButton!
// Variables
var timer = Timer()
var time: Int = 0
var running: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
roundButtons()
}
#IBAction func resetTimer(_ sender: Any) {
timer.invalidate()
time = 0
updateUI()
running = false
}
#IBAction func startTimer(_ sender: Any) {
if running {
return
} else {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerDidEnd), userInfo: nil, repeats: true)
running = true
}
}
#IBAction func pauseTimer(_ sender: Any) {
timer.invalidate()
running = false
}
func roundButtons() {
resetButton.layer.cornerRadius = resetButton.frame.height / 2
startButton.layer.cornerRadius = startButton.frame.height / 2
pauseButton.layer.cornerRadius = pauseButton.frame.height / 2
}
#objc func timerDidEnd() {
time += 1
updateUI()
}
func updateUI() {
var min: Int
var sec: Int
var mil: Int
min = time / (60*60)
sec = (time/60)%60
mil = time & 60
minutes.text = String(min)
seconds.text = String(sec)
milliSecondsLabel.text = String(mil)
}
}
I'd suggest two things:
Don’t try to count the time elapsed yourself. Capture the start time and calculate the elapsed time from that. You can use Date method timeIntervalSince, or, because that's not guaranteed to return monotonically increasing values, use CACurrentMediaTime, like below.
Rather than having a timer with an arbitrary 100 updates per second, instead use a CADisplayLink, which is optimally timed for device screen refresh rates.
E.g.:
class ViewController: UIViewController {
// Outlets
#IBOutlet weak var minutesLabel: UILabel!
#IBOutlet weak var secondsLabel: UILabel!
#IBOutlet weak var milliSecondsLabel: UILabel!
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var pauseButton: UIButton!
// Variables
private weak var displayLink: CADisplayLink?
private var startTime: CFTimeInterval?
private var elapsed: CFTimeInterval = 0
private var priorElapsed: CFTimeInterval = 0
override func viewDidLoad() {
super.viewDidLoad()
setFonts()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
roundButtons()
}
#IBAction func resetTimer(_ sender: Any) {
stopDisplayLink()
elapsed = 0
priorElapsed = 0
updateUI()
}
#IBAction func startTimer(_ sender: Any) {
if displayLink == nil {
startDisplayLink()
}
}
#IBAction func pauseTimer(_ sender: Any) {
priorElapsed += elapsed
elapsed = 0
displayLink?.invalidate()
}
}
private extension ViewController {
func startDisplayLink() {
startTime = CACurrentMediaTime()
let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
displayLink.add(to: .main, forMode: .common)
self.displayLink = displayLink
}
func stopDisplayLink() {
displayLink?.invalidate()
}
#objc func handleDisplayLink(_ displayLink: CADisplayLink) {
guard let startTime = startTime else { return }
elapsed = CACurrentMediaTime() - startTime
updateUI()
}
func updateUI() {
let totalElapsed = elapsed + priorElapsed
let hundredths = Int((totalElapsed * 100).rounded())
let (minutes, hundredthsOfSeconds) = hundredths.quotientAndRemainder(dividingBy: 60 * 100)
let (seconds, milliseconds) = hundredthsOfSeconds.quotientAndRemainder(dividingBy: 100)
minutesLabel.text = String(minutes)
secondsLabel.text = String(format: "%02d", seconds)
milliSecondsLabel.text = String(format: "%02d", milliseconds)
}
func roundButtons() {
resetButton.layer.cornerRadius = resetButton.bounds.height / 2
startButton.layer.cornerRadius = startButton.bounds.height / 2
pauseButton.layer.cornerRadius = pauseButton.bounds.height / 2
}
func setFonts() {
minutesLabel.font = UIFont.monospacedDigitSystemFont(ofSize: minutesLabel.font.pointSize, weight: .regular)
secondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: secondsLabel.font.pointSize, weight: .regular)
milliSecondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: milliSecondsLabel.font.pointSize, weight: .regular)
}
}
That yields:
Completely unrelated, but anything dependent upon the size of views (e.g. the corner rounding) really belongs in viewDidLayoutSubviews, not viewDidLoad.
I have a label. And I have 3 strings. I need to display text of 3 strings in the same label with delay of 10 seconds over a infinite loop. How can i solve this with simple animations in swift 3?
That's my solution. Just connect a UILabel to the IBOutlet
class ViewController: UIViewController {
#IBOutlet weak var textLabel: UILabel!
let messages = ["PROFESSIONAL AND BEST LEARNING CENTER","LEARNING TECHNOLOGY AND DESIGN IN A SMART WAY","EXPLORE YOUR SKILLS"]
let delayTime = 10.0
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(timeInterval: delayTime, target: self, selector: #selector(changeDisplayedText), userInfo: nil, repeats: true)
timer.fire()
}
func changeDisplayedText() {
textLabel.text = messages[counter % messages.count]
counter += 1
}
}
This will work for your, connect your outlet properly and declare those string in an array and load it with timer change.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var array = ["Aaaaaaaaaaa", "Bbbbbbbbbbb", "Ccccccccccc"]
var scrollIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.myDelayedFunction), userInfo: nil, repeats: true)
timer.fire()
}
func myDelayedFunction()-> Void {
let count = self.array.count
if scrollIndex == count {
scrollIndex = 0
}
if scrollIndex < count {
if count > 1{
self.label.text = array[scrollIndex]
self.scrollIndex += 1
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I´m trying to update my #IBOutlet weak var gameclockLabel: UILabel! from my class Gameclock with delegate.
I have read and tested about a million different ways but can't make it work. I think that the more I read about it the more confused I get.
You can read more about what I'm trying to do here:
swift invalidate timer in function
From the answers in that question I added this: var gameClock = Gameclock() so I was able to start a function in class Gameclock and first I tried to do the same with my class ViewController: UIViewController but that didn't work so that's why I decided to try with delegate instead. Do you think delegate is the right way to go with this?
I'm going to add several timers in separate classes to this later on so perhaps there's a better way.
Would be nice if someone could point me in the right direction. At first I thought this would be not to complicated but seems I was mistaking :)
The complete code is as follows:
import UIKit
protocol test1: class {
func updateLabel()
}
class ViewController: UIViewController, test1 {
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidLoad() {
super.viewDidLoad()
gameclockLabel.text = "00:00"
}
var gameClock = Gameclock()
var startstopPushed: Bool = false
#IBOutlet weak var gameclockLabel: UILabel!
#IBOutlet weak var startstop: UIButton!
#IBAction func startStopbutton(sender: AnyObject) {
if startstopPushed == false {
gameClock.startGameclock()
startstop.setImage(UIImage(named: "stop.png"), forState: UIControlState.Normal)
startstopPushed = true
}
else
{
gameClock.stopGameclock()
startstop.setImage(UIImage(named: "start.png"), forState: UIControlState.Normal)
startstopPushed = false
}
}
func updateLabel() {
print("updated")
gameclockLabel.text = gameClock.timeString
}
}
class Gameclock : NSObject {
var gameclockTimer = NSTimer()
var timeString: String = ""
var seconds = 0
var minutes = 0
weak var delegate: test1?
func startGameclock() {
print("start")
gameclockTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateGameclock"), userInfo: nil, repeats: true)
}
func stopGameclock() {
self.gameclockTimer.invalidate()
print("stopp")
}
func updateGameclock() {
seconds += 1
if seconds == 60 {
minutes += 1
seconds = 0
}
let secondsString = seconds > 9 ? "\(seconds)" : "0\(seconds)"
let minutesString = minutes > 9 ? "\(minutes)" : "0\(minutes)"
timeString = "\(minutesString):\(secondsString)"
print(timeString)
delegate?.updateLabel()
}
}
You haven't actually set your ViewController instance as your GameClocks delegate, so your updateLabel method won't be called;
override func viewDidLoad() {
super.viewDidLoad()
gameclockLabel.text = "00:00"
self.gameClock.delegate=self
}
I am trying to display different text within a label after a period of time using a timer, but cant increment the element of my custom type array.
Here is the code:
import UIKit
class WorkWorkoutViewOne: UIViewController {
#IBOutlet weak var exerciseTitle: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var instructionsLabel: UILabel!
#IBOutlet weak var exerciseImage: UIImageView!
var counter = 15
var timer: NSTimer?
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
let image: UIImage = workoutExercisesShuffled[0].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[0].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[0].instructions
instructionsLabel.text = instructionsTitle
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerAction", userInfo: nil, repeats: true)
}
var timerTwo: NSTimer?
var counterTwo = 15
func timerAction() {
--counter
timerLabel.text = "\(counter)"
if (counter == 0) {
timer?.invalidate()
let image: UIImage = workoutExercisesShuffled[1].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[1].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[1].instructions
instructionsLabel.text = instructionsTitle
timerLabel.text = "\(counterTwo)"
var timerTwo = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerActionTwo", userInfo: nil, repeats: true)
}
}
Repeating this method using timerThree, timerFour etc. seems clumbsy and unnecessary, so would like a way to increment the array values rather than having to call seperately in different functions.
Try this, it uses two methods and an index.
Workflow
Initially index is set to 0 and counter is set to 15.
updateExercise() is called.
The exercise UI is updated.
If index is 0 the timer is created.
timerAction() is called after the timer fires.
The counter is decremented and the counter label is updated.
If counter is 0 and index is equal to the number of exercises -1 the timer is invalidated.
If counter is 0 and index < number of exercises -1 index is incremented, counter is reset to 15 and updateExercise() is called again.
var counter = 15
var index = 0
var timer: NSTimer?
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
updateExercise()
}
func updateExercise() {
let image: UIImage = workoutExercisesShuffled[index].filename!
exerciseImage.image = image
let titleLabel = workoutExercisesShuffled[index].name
exerciseTitle.text = titleLabel
let instructionsTitle = workoutExercisesShuffled[index].instructions
instructionsLabel.text = instructionsTitle
if index == 0 {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerAction", userInfo: nil, repeats: true)
}
}
func timerAction() {
counter -= 1
timerLabel.text = "\(counter)"
if (counter == 0) {
if index == workoutExercisesShuffled.count - 1 {
timer!.invalidate()
timer = nil
} else {
index += 1
counter = 15
updateExercise()
}
}
}
I did not test this, but it should work.
import UIKit
class WorkWorkoutViewOne: UIViewController {
#IBOutlet weak var exerciseTitle: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var instructionsLabel: UILabel!
#IBOutlet weak var exerciseImage: UIImageView!
var count = 15
var index = 0
var timer: NSTimer
var countdown: NSTimer
var workoutExercisesShuffled = [Exercise]()
override func viewDidLoad() {
super.viewDidLoad()
// TODO: load your exercises
var timer = NSTimer.scheduledTimerWithTimeInterval(15, target: self, selector: "displayNewExercise", userInfo: nil, repeats: true)
}
func displayNewExercise() {
countdown = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "displayCountdown", userInfo: nil, repeats: true)
if (index < workoutExercisesShuffled.count) {
exerciseImage.image = workoutExercisesShuffled[index].filename!
exerciseTitle.text = workoutExercisesShuffled[index].name
instructionsLabel.text = workoutExercisesShuffled[index].instructions
++index
}
else {
timer.invalidate()
countdown.invalidate()
}
}
func displayCountdown() {
if(count > 0) {
countDownLabel.text = String(--count)
}
else {
countdown.invalidate()
count = 15
}
}
}
Don't repeat yourself. A certain task can be done only by one function, the code for this particular task must not be elsewhere.
This question already has an answer here:
Swift Version 2 Bool [closed]
(1 answer)
Closed 7 years ago.
I'm having some issues running an App using Swift v2. Stopping the tmrRun is one issue. I know how to [tmrRun invalidate] in Objective C but not in Swift v2. Any help would be appreciated.
class ViewController: UIViewController {
#IBOutlet var imvWolf: UIImageView!
#IBOutlet var btnGo: UIButton!
#IBOutlet var btnStop: UIButton!
#IBOutlet var sliSpeed: UISlider!
var pic = 0
var tmrRun: NSTimer?
#IBAction func startRunnng(sender: UIButton)
{
tmrRun = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
btnGo.userInteractionEnabled = false
btnStop.userInteractionEnabled = true
sliSpeed.userInteractionEnabled = false
}
#IBAction func stopRunnng(sender: UIButton)
{
[tmrRun invalidate]
btnGo.userInteractionEnabled = true
btnStop.userInteractionEnabled = false
sliSpeed.userInteractionEnabled = true
}
func takeABound() -> ()
{
pic += 1;
if (pic == 8){
pic = 0;
}
}
override func viewDidLoad() {
super.viewDidLoad()
pic = 0;
// 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.
}
}
To stop the timer is definitely timername.invalidate(), but remember you have to also stop the animation:
timername.invalidate()
isAnimating = false
If doing this you still have issues I think the problem it's where you're typing it.
Try it using this code:
#IBAction func playButton(sender: AnyObject) {
moveWolf()
}
#IBAction func pauseButton(sender: AnyObject) {
timername.invalidate()
isAnimating = false
}
func moveWolf(){
//Here instead of 0.1 you set the slider value
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("doAnimation"), userInfo: nil, repeats: true)
isAnimating = true
}
func doAnimation(){
if counter == 5 {
counter = 1
}
else{
counter++
}
imatge.image = UIImage(named: "picture\(counter).png")
}
Hope that helps you! Good luck!