0

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

gamerounet
  • 279
  • 4
  • 22

1 Answers1

1

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() }
    }
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • I know it's a bit old, but I realize that after the last request I got a problem. All my first request works well, but when I have to loop every 60 seconds: - first call, t+10, +20, +40, +60 are ok, but when I wait 60 more second ,instead of sending a new request, i got : 2021-01-11 18:20:16.082425 testApplication[21471:288583] Received XPC error Connection interrupted for message type 3 kCFNetworkAgentXPCMessageTypePACQuery 2021-01-11 18:20:16.082680 testApplication[21471:288583] Received XPC error Connection invalid for message type 3 kCFNetworkAgentXPCMessageTypePACQuery Any idea? – gamerounet Jan 11 '21 at 17:22
  • 1
    sorry I didn't realize what was the best way to ask it. I thought creating a new post with an additional question about the same subject was no the way to do, but for sur your first answer totally resolve the initial problem, so there was no reason to remove the accepted flag. I accepted it again, sorry for the inconvenient and thanks again for your previous helpp – gamerounet Jan 11 '21 at 20:31