Simple NSTimer implementation issue - ios

I have just started to learn swift 2 and I am testing a few things in an Xcode 'playground'. When a create an instance of the 'pyx' (below) I am not seeing the console output I would expect. I am sure I have made a silly mistake but after staring at it for a while I cannot figure it out.
class zxy {
var gameTimer = NSTimer()
var counter = 0
init() {
gameTimer = NSTimer (timeInterval: 1, target: self, selector: "Run:", userInfo: nil, repeats: true)
}
func Run(timer : NSTimer) {
while(counter < 10){
print(counter)
counter++
}
timer.invalidate()
}
}
Thanks in advanced.

You have 2 problems with your code. As #glenstorey points out in his answer, you need to call the method scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, not the init method you're calling.
EDIT:
As #DanBeauleu says in his comment to my answer, the call would look like this in Swift:
NSTimer.scheduledTimerWithTimeInterval(
1,
target: self,
selector: "Run:",
userInfo: nil,
repeats: true)
The second problem is your Run method.
You don't want a while loop. That will repeat 10 times in a tiny fraction of a second the first time the timer fires, then invalidate the timer.
Your timer method needs to be changed like this:
func Run(timer : NSTimer)
{
if counter < 10
{
print(counter)
counter++
}
else
{
timer.invalidate()
}
}
(BTW, by strong convention, method/function names should start with a lower-case letter, so your Run function should be named run instead.)

You've created a NSTimer object, but that doesn't start the timer - just gets it ready to go. Use scheduledTimerWithTimeInterval to create and start the timer.

Related

while loop not executing with timer

I'm pretty new to Swift, been practicing for about a week now. I've declared a timer, I call the function of the timer with viewDidLoad(), and the timers #selector points to goldPerSec, that function is a simple while loop, yet it's not executing every second as it should.
Here's my code:
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
counter()
}
func counter() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.goldPerSec), userInfo: nil, repeats: true)
}
#objc func goldPerSec() {
while (totalOwned >= 1) {
Gold += (minerOwned * 1)
goldLabel.text = "\(Gold)"
}
}
Your while loop in goldPerSec runs forever preventing any other code from running on the main queue, including the timer.
Change the while loop to an if statement.
#objc func goldPerSec() {
if totalOwned >= 1 {
Gold += minerOwned * 1
goldLabel.text = "\(Gold)"
}
}
This will now allow goldPerSec to be called every second from the timer and also allow the rest of your user interface to work.
As a side note, variable names should start with lowercase letters so Gold should be named gold.

Type 'GameScene has no member 'delay'

I declared delay and it is giving me an error, I am trying to slow down the timer.
//Updates Timer
func updateTimer() {
var delay: Int
seconds += 1
self.timerLabel.text = String(self.seconds * 0.01)
timer = NSTimer.scheduledTimerWithTimeInterval(-2.0, target: self, selector: #selector(GameScene.delay), userInfo: nil, repeats: false)
The message is telling you that there is no selector for GameScene.delay. You need a func that matches this name. Note that because you have used "GameScene" rather than "gameScene", it may be a class, in which case you would need a "class func" called delay. However, more likely is you would want "self.delay" to be called. ie. one of
func delay(timer: NSTimer) { ... }
class func delay(timer: NSTimer) { ... }
Also, what are you trying to achieve with "-2.0"? You can't run a timer in the past - if will default to 0.1 if <= 0.
the selector portion of a NSTimer is meant to run a function so you declare the function then the timer should be placed outside of the function instead of inside the function
func updateTimer() {
var delay: Int
seconds += 1
self.timerLabel.text = String(self.seconds * 0.01)}
let timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: false)
also could you be more specific when you say you are trying to slow down the timer so

Swift: prevent NSTimer starting automatically

I am trying to use the NSTimer to increment the progress bar in my app when recording voice (see the screenshot)
let timedClock = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Counting:"), userInfo: nil, repeats: true)
internal func Counting(timer: NSTimer!) {
if timeCount == 0 {
//self.timedClock = nil
stopRecording(self) //performs segue to another view controller
} else {
timeCount--;
self.timer.text = "\(timeCount)"
}
print("counting called!")
progressBar.progress += 0.2
}
The progress bar works only for the first time after I compile and run the project. When the recording is finished, the app performs segue to another view controller to play the recorded audio. However, when I go back to the view for recording, the timer/progress bar automatically runs. I suspect the NSTimer object is still alive on the NSRunLoop. So I was wondering how to prevent the NSTimer from automatically running.
Inspired by the answer in this SO thread, I tried the following, but the NSTimer still automatically runs.
let timedClock = NSTimer(timeInterval: 1, target: self, selector: "Counting:", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timedClock, forMode: NSRunLoopCommonModes)
This happens because when your controller created it's properties are automatically initialized. According to Apple Docs (and method's name) scheduledTimerWithTimeInterval create and return scheduled timer. So if you only want create your timer and call it by trigger function use it like this:
class MyClass {
var timer: NSTimer?
...
func enableTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Counting:"), userInfo: nil, repeats: true)
}
func disableTimer() {
timer?.invalidate()
timer = nil
}
...
}
Sorry for the quick self-answer, as I just found out that I can use the invalidate() method to prevent the timer from automatically firing:
timedClock.invalidate()
Hope it helps someone in the future!

How to wait a given time to run an action-SWIFT

I would like to know how to run an action after making the console count a given time. For example printing 'hello' after 3 seconds.
Thank you!!
You need to use the NSTimer class.
Example usage:
var timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("sayHello"), userInfo: nil, repeats: true)
Somewhere else in your class...
func sayHello() {
println("Hello")
}
You can create delays with following ways!!
You can create a delay using asynAfter
DispatchQueue.main.asyncAfter(deadline: .now() + <secondsToDelay>) {
// Put your code here that you want to execute after delay
}
Another way is calling a function itself after a delay using objc's perform selector
perform(#selector(delayedMethod), with: nil, afterDelay: <secondsToDelay>)
#objc func delayedMethod() {
print("My delayed method call")
}
Of course you can also use Timer like in Woodstock's answer.

Make a service call at regular interval of time in swift

I am new to swift programming and I don't know how to call a method at regular interval of time. I have a demo app for service call but i don't know how can i call it at regular interval of time.
You can create an object of NSTimer() and call a function on definite time interval like this:
var updateTimer = NSTimer.scheduledTimerWithTimeInterval(15.0, target: self, selector: "callFunction", userInfo: nil, repeats: true)
this will call callFunction() every 15 sec.
func callFunction(){
print("function called")
}
Here is a simple example with start and stop functions:
private let kTimeoutInSeconds:NSTimeInterval = 60
private var timer: NSTimer?
func startFetching() {
self.timer = NSTimer.scheduledTimerWithTimeInterval(kTimeoutInSeconds,
target:self,
selector:Selector("fetch"),
userInfo:nil,
repeats:true)
}
func stopFetching() {
self.timer!.invalidate()
}
func fetch() {
println("Fetch called!")
}
If you get an unrecognized selector exception, make sure your class inherits from NSObject or else the timer's selector won't find the function!
Timer variant with a block (iOS 10, Swift 4)
let timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { (timer) in
print("I am called every 5 seconds")
}
Do not forget call invalidate method
timer.invalidate()
GCD approach (will tend to drift a bit late over time)
func repeatMeWithGCD() {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
print("I am called every 5 seconds")
self.repeatMeWithGCD()//recursive call
}
}
Do not forget to create a return condition to prevent stackoverflow error

Resources