-1

I am using the following code to invoke a function periodically every second. The problem is delay is actually 1.1 seconds and gets drifted more and more eventually as can be seen in NSLogs (and it is visible in other parts of the code as well apart from NSLog). Am I doing it wrong, or should I be using timer?

private func updateTimeCode() {
    NSLog("Updating time")
    //Some more code that doesn't take time
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
        [weak self] in
            self ? .updateTimeCode()
    }
}
 019-08-06 17:15:19.713234+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:20.812652+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:21.913188+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:23.028814+0530 MyApp-Swift[8299:2685215] Updating time
Milo
  • 3,365
  • 9
  • 30
  • 44
Deepak Sharma
  • 5,577
  • 7
  • 55
  • 131
  • I am not using a background queue. It's on the main queue. Is that wrong? – Deepak Sharma Aug 06 '19 at 11:58
  • 1
    Perhaps, if you do any other task on main queue. there'll be some issues invoking the function as there'a only one Main queue available. Use Timer class as suggested above. – Tushar Katyal Aug 06 '19 at 12:01
  • How do I program a background timer in Swift that can be paused and resumed? – Deepak Sharma Aug 06 '19 at 12:08
  • https://www.hackingwithswift.com/example-code/system/how-to-make-an-action-repeat-using-timer timer.pause() – Tushar Katyal Aug 06 '19 at 12:10
  • This is better but need to find a working code - https://medium.com/over-engineering/a-background-repeating-timer-in-swift-412cecfd2ef9 – Deepak Sharma Aug 06 '19 at 12:11
  • Are you trying to run a timer when app is in background state ? – Tushar Katyal Aug 06 '19 at 12:12
  • No, because lot of high priority processing goes in main queue, maybe timer can be run in background queue. – Deepak Sharma Aug 06 '19 at 12:15
  • Timer works on different thread/Queue only. that's the answer for your question. – Tushar Katyal Aug 06 '19 at 12:16
  • That's not correct. It needs work to move it to background thread. – Deepak Sharma Aug 06 '19 at 12:38
  • 1
    Unrelated but `[weak self]` is pointless. GCD closures don't cause retain cycles. Use `DispatchSourceTimer`. It's much more reliable. – vadian Aug 06 '19 at 13:33
  • 1
    @vadian I agree that blocks submitted to GCD don't cause permanent retain cycles, but they still prevent `self` from deallocating until the block executes, which may or may not be desirable depending on the situation. In this specific case, allowing `self` to be strong *would* create a cycle because every time the block fires it reschedules itself, so `weak` is doing its job here (but agree that DispatchSourceTimer is probably the right tool). – Rob Napier Aug 06 '19 at 14:52
  • @vadian just curious, why is DispatchSourceTimer more reliable? – Deepak Sharma Aug 06 '19 at 16:42
  • @RobNapier is there a retain cycle if the timer eventually is made to stop? – Deepak Sharma Aug 06 '19 at 16:43
  • @DeepakSharma Please read Rob's answer in https://stackoverflow.com/questions/55131532/difference-between-dispatchsourcetimer-timer-and-asyncafter – vadian Aug 06 '19 at 16:47
  • @DeepakSharma There is no way to make your implementation of the timer stop. But if there were, it would depend on the implementation whether it removed the retain cycle. – Rob Napier Aug 06 '19 at 17:52
  • @RobNapier I meant by setting timer?.invalidate() & timer = nil, will that not remove retain cycle? – Deepak Sharma Aug 07 '19 at 08:45
  • @DeepakSharma oh, that will break the retain loop for Timer. I thought you meant for your asyncAfter implementation. – Rob Napier Aug 07 '19 at 12:53

1 Answers1

1

It's because of the part that you say some more code not relevant taking time. They take time and time passes between each invocation of asyncAfter so basically .now() becomes something more than exactly 1 second ago.

Anyway, it's not a conventional way to achieve it. You need to use timer for that purpose. Here's a useful tutorial about how to use it. Timer in Swift

Yusuf Kamil AK
  • 771
  • 8
  • 17