Search code examples
iosswiftasynchronoustimerkotlin-coroutines

Set a timer with variable intervals in swift


I need to set a specific timer asynchronously after executing an action like this:

  1. calling my function (sending http request)
  2. 10 seconds after, sending another request
  3. 20 seconds after 2), sending another one
  4. 40 seconds after 3), another one
  5. then send every 60 seconds another one

At any moment, I must be able to cancel my timer. Firstable I thought using DispatchQueue, but I see several post saying that it's not possible to cancel it.

Some post suggest to use DispatchWorkItem ( how to stop a dispatchQueue in swift ) but I'm not sur it fit my need (unless adding a sleep(10,20,40,60...) in each loop but will it not impact asynchronous part?).

Another answer from this post suggest to use Timer instead ( scheduledTimerWithTimeInterval ) with repeats:false, and invalidate it after each loop, but I didn't undertand how to do the loop in this case. Actually, here's my code, that just send a request after 10 seconds:

  private func start() {
        timer?.invalidate()
        if(self.PCount > self.Intervals.count){
            self.value = self.pollingIntervals.count-1
        } else {
            self.Value = self.Intervals[self.pCount]
        }
        print("set timer with \(pollingValue) as interval")
        timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(pollingValue), repeats: false, block: { timer in
            self.sessionManager.sendHit()
            self.pollingCount+=1

        })
}

The current goal is to do something like coroutine in Kotlin, like it work with this code :

private val Intervals = longArrayOf(10000,20000,40000,60000)
private var Count = 0   
 
private fun start() {
    currentJob = GlobalScope.launch {
        while (true) {
            delay(Intervals[if (Count > Intervals.size) Intervals.size - 1 else Count]) // 10,20,40 then every 60
            session.sendHit()
            pollingCount++
        }
    }
}

I'm not sure what solution is the most appropriate to my project


Solution

  • Here is a basic idea on how to approach the problem

    struct RequestMananger {
        var timers: [Timer] = []
    
        mutating func startSequence() {
            var delay = 10.0
            sendRequest()
    
            timers.append(scheduleTimer(delay))
            delay += 20
            timers.append(scheduleTimer(delay))
            delay += 40
            timers.append(scheduleTimer(delay))
            delay += 60
            timers.append(scheduleTimer(delay, repeats: true))
        }
    
        private func scheduleTimer(_ delay: TimeInterval, repeats: Bool = false) -> Timer {
            return Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { timer in
                self.sendRequest()
            })
        }
    
        func sendRequest() {
            
        }
    
        func cancelTimers() {
            timers.forEach { $0.invalidate() }
        }
    }