Timer.scheduledTimer not working in Swift 3

I want to call the func adjustmentBestSongBpmHeartRate() method every 1.1 seconds. I used a timer, but it does not work. I read the document and found many code examples, it still works! Did I miss something?

  timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false) timer.fire() func adjustmentBestSongBpmHeartRate() { print("frr") } 
+14
source share
9 answers

I found that creating a timer in OperationQueue Operation does not work. I guess this is because there is no runloop.

So the following code solved my problem:

 DispatchQueue.main.async { // timer needs a runloop? self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false) } 
+23
source

The timer methods with the selector must have one parameter: the timer itself. So your code should look like this: 1

 Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate(_:), userInfo: nil, repeats: false) @objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) { print("frr") } 

Please note that if your application only runs on iOS> = 10, you can use the new method, which uses a block rather than a target / selector to call. Much cleaner and safer:

 class func scheduledTimer(withTimeInterval interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Void) -> Timer 

This code will look like this:

  timer = Timer.scheduledTimer(withTimeInterval: 1.1, repeats: false) { timer in //Put the code that be called by the timer here. print("frr") } 

Note that if your timer / close block needs access to instance variables from your class, you should be especially careful with self . Here is a good template for this kind of code:

  timer = Timer.scheduledTimer(withTimeInterval: 1.1, repeats: false) { //"[weak self]" creates a "capture group" for timer [weak self] timer in //Add a guard statement to bail out of the timer code //if the object has been freed. guard let strongSelf = self else { return } //Put the code that be called by the timer here. print(strongSelf.someProperty) strongSelf.someOtherProperty = someValue } 

Edit:

1 : I have to add that the method you use in the selector should use Objective-C dynamic dispatch. You can declare a method using the @objc qualifier, you can declare an entire class that defines a selector using the @objc qualifier, or you can make a class that defines a selector a subclass of NSObject or any class that inherits from NSOBject . (Quite often, a method is defined that the timer calls inside the UIViewController , which is a subclass of NSObject , so it "just works."

EDIT

In Swift 4, methods that must be called from Objective-C must now be individually tagged with the @objc qualifier. The comment β€œit just works” is no longer true.

+20
source

Swift 3

In my case, it worked after I added the @obj prefix to my method

 Class TestClass { private var timer: Timer? func start() { guard timer == nil else { return } timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(handleMyFunction), userInfo: nil, repeats: false) } func stop() { guard timer != nil else { return } timer?.invalidate() timer = nil } @objc func handleMyFunction() { // Code here } } 
+10
source

Try it -

 if #available(iOS 10.0, *) { self.timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in self.update() }) } else { self.timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.update), userInfo: nil, repeats: false) } 

Basically, the problem was supposed to be due to the iOS version for mobile devices.

+5
source

I solved the question asked by me. I am using apple watch to control my iphone application. I'm trying to press a button on the apple hour to submit a new view manager on iphone.

When I write a timer in override func viewDidLoad() , the timer does not work. I move the timer to override func viewWillAppear() , it works.

I think maybe something is wrong with apple control


+2
source

I found that if you try to initialize the timer directly at the class level, it will not work if you are targeting a selector in the same class. When it fires, it cannot find the selector.

To get around this, I only initialize the timer after the object containing the selector has been initialized. If it is in the same class, put the initialization code in ViewDidLoad or similar. Just not in the initializer. Then it will work. A dispatch queue is not required.

In addition, you do not need to use a selector that takes a timer as a parameter. You can, but contrary to the answer with a ton of votes, that this is actually not the case, or, more precisely, it works fine for me without it, just as you do without it.

By the way, I think that the reason the send queue has worked is because you force the timer to be created after the object is initialized, confirming my statement above.

 let timer:Timer? override func viewDidLoad(){ super.viewDidLoad() timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false) timer.fire() } func adjustmentBestSongBpmHeartRate() { print("frr") } 

Note. This is code typed from memory, not copied from Xcode, so it may not compile, but I hope you get the idea.

+1
source

Swift 5, Swift 4 An easy way to call only with an asynchronous send queue

 DispatchQueue.main.async { self.andicator.stopAnimating() self.bgv.isHidden = true Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { _ in obj.showAlert(title: "Successfully!", message: "Video save successfully to Library directory.", viewController: self) }) } 
+1
source

Swift3

 var timer = Timer() timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.compruebaConexion), userInfo: nil, repeats: true) 
0
source

my two cents. I read about "didLoad" and on call. so we can use the delay:

 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) } 
0
source

Source: https://habr.com/ru/post/1012347/


All Articles