Timer on swift not working - swift

I have a function working with a button:
#IBAction func btnSiguiente(_ sender: Any) {
if indexImagenes == imagenes.count {
indexImagenes = 0
}
escaparate.image = NSImage(named: imagenes[indexImagenes])
indexImagenes += 1
}
I want to make it work with a Timer:
var playTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(autoplay), userInfo: nil, repeats: true)
func autoplay() {
if indexImagenes == imagenes.count {
indexImagenes = 0
}
escaparate.image = NSImage(named: imagenes[indexImagenes])
indexImagenes += 1
}
But I get this in console:
[_SwiftValue autoplay]: unrecognized selector sent to instance 0x6080000451c0

To fix this, initialize the timer once the instance of the class your are in is fully initialized.
So just give the var playTimer a default value as follows:
var playerTimer:Timer? = nil
Then initialize the timer in some function that gets called once 'self' is fully initialized (like viewDidLoad() for example, assuming this code is in a viewController):
override func viewDidLoad()
{
super.viewDidLoad()
playerTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(autoplay), userInfo: nil, repeats: true)
}
Essentially just make sure 'self' is fully initialized before you send it a selector to perform.

Related

Swift 5 - Timer not firing

I have the following,
class someViewController : ViewController{
var timer:Timer? = nil
override func viewDidLoad() {
timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(fire), userInfo: nil, repeats: true)
}
#objc func fire(){
print("fired")
}
}
The fire function is never hit and I can't figure out why, what am I missing?
Try to clean Xcode or rebuild project, because your code works fine.

Swift timer method terminates the app early with SIGABRT error

Below is my code for having a timer change a variable from 0 to 1, which results in a SIGABRT error when the timer tries to fire:
var timerToggle = 0
let timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: false)
#objc func fireTimer() {
timerToggle = 1
}
I know others who've had this problem seem to solve it by placing the timer declaration within the override func viewDidLoad() function but whenever I do that it gives me the following error
"Initialization of immutable value 'timer' was never used; consider replacing with assignment to '_' or removing it."
Any help would be greatly appreciated
"Initialization of immutable value 'timer' was never used; consider
replacing with assignment to '_' or removing it."
This is just a warning not an error. You can still go ahead and initialise timer in viewDidLoad.
If it is needed to activate once-fired timer in viewDidLoad, it should look somehow like the following
class MyController: UIViewController {
var timerToggle = 0
private var timer: Timer?
deinit {
timer?.invalidate()
}
#objc func fireTimer() {
timerToggle = 1
timer = nil
}
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 5.0, target: self,
selector: #selector(fireTimer), userInfo: nil, repeats: false)
}
}
If you are not going to access the timer anymore simply add below to viewDidLoad
_ = Timer.scheduledTimer(timeInterval: 5.0,
target: self,
selector: #selector(fireTimer),
userInfo: nil,
repeats: false)

Countdown speeds up when the button that starts it is pressed multiple times

I just started to learn swift . and I found when using a button to start a count down if i pressed the button twice it speeds up the process. What to add to prevent that?
#IBAction func startButton(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(processTime), userInfo: nil, repeats: true)
}
#objc func processTime(){
if counter > 0 {
counter -= 1
timeLabel.text = "\(counter)"
}else {
timer.invalidate()
}
}
I tried to use sender.isEnabled = false it gave this error (Value of type 'Any' has no member 'isEnabled')
so I did it like this :
#IBAction func startButton(_ sender: Any) {
if timer.isValid != true{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(processTime), userInfo: nil, repeats: true)
}
}
Many ways, depends on what logic you prefer.
Basically you need to ensure that the timer starts only once until it completes.
In the following example, we start the timer only if it's not been initialized previously.
Furthermore, when we stop the timer, we explicitly set it to nil so the following logic works again after the timer completes.
//globally declared as optional
var timer: Timer?
#IBAction func startButton(_ sender: Any) {
//check if timer is nil
if timer != nil {
//start timer only if timer is nil
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(processTime),
userInfo: nil,
repeats: true)
}
}
#objc func processTime() {
if counter > 0 {
counter -= 1
timeLabel.text = "\(counter)"
}
else {
timer.invalidate()
//clear the timer
timer = nil
}
}
add a sender.isEnabled = false and after you press the button once it won't be clickable again
You need to invalidate the timer by calling timer.invalidate() before you reassign a new timer. If you assign a new timer instance to the old one without invalidating, you will lose reference to it and it will never be invalidated.

Swift Timer error when function has arguments

I'm trying to make a function that activates every one second, which adds 1 to a variable (texttimer) and adds a letter to a string (typedStory), which is displayed on a label (storyLabel).
Everything worked fine until I added an argument (finalStory) to the function. Now I'm getting an an error:
-[__NSCFTimer substringToIndex:]: unrecognized selector sent to instance
Here's the code I have:
func textTypeWelcome(finalStory: NSString){
var newTimer2 = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(GameScene.textTypeWelcome), userInfo: finalStory, repeats: false)
texttimer += 1
typedStory = finalStory.substring(to: texttimer)
storyLabel.text = typedStory
}
The code works, however doesn't do what I want if I remove the argument and put userInfo to nil.
Anyone know of a solution? Thanks!
No, that cannot work, the action method takes the timer as parameter – what the error message tells you – and you get finalStory from the userInfo parameter.
func textTypeWelcome(timer: Timer) {
let finalStory = timer.userInfo as! String
var newTimer2 = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(GameScene.textTypeWelcome), userInfo: finalStory, repeats: false)
texttimer += 1
typedStory = finalStory.substring(to: texttimer)
storyLabel.text = typedStory
}
Try this out in a Playground
class Foo : NSObject {
let string = "Hello World"
var counter = 1
var typedStory = ""
var timer = Timer()
override init() {
super.init()
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
print("timer started")
}
func timerFired(timer : Timer) {
typedStory = string.substring(to: string.index(string.startIndex, offsetBy: counter))
print(typedStory)
if typedStory == string {
timer.invalidate()
print("timer stopped")
} else {
counter += 1
}
}
}
let foo = Foo()
You have to add the lines
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
to allow asynchronous API

Swift 3 Timer Function in GameScene.Swift

I have a timer function that works in the viewcontroller.swift file here:
override func viewDidLoad() {
super.viewDidLoad()
//Swift 3 selector syntax
var timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
// must be internal or public.
func update() {
// Something cool
}
I need to get it to work in my gamescene.swift file. This is what I had that wasn't working:
var currentTimeSeconds = 0
override public func didMove(to view: SKView) {
var timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(update), userInfo: nil, repeats: true)
}
public func update() {
currentTimeSeconds = currentTimeSeconds + 1
}
I keep getting the error "ambiguous use of 'update.'"