Why does recursive Dispatch.main.async take longer and longer?

So I have this recursive function in SwiftUI. Each iteration takes on average 50 ms on a late model iPhone. The whole thing will take a minute or so. When the user kicks it off he expects this and has nothing else to do in the app until the exit condition is reached and it is done. But of course I want it to finish as soon as possible and I want the user to be able to abort it early if he becomes impatient. Also after each iteration it updates a line chart to show its progress to the user. For speed, I’m running it on the main thread like this:

 .onChange(of: kickItOff) { value in
    recursiveFunction()
 }

func recursiveFunction() {
    Dispatch.main.async() {
        step1()
        step2()
        step3()
        if !exit {
            recursiveFunction()
        }
    }
}

Each step in an iteration and the iterations themselves must execute serially. This runs fast and the UI is not blocked. Just one problem. Each time it is kicked off it takes longer and longer to finish. The 4th run takes twice as long as the 1st. I profiled it with the signpost instrument and can see that each step in the recursive function does not change duration from iteration to iteration. It is the time gap between iterations that increases. Does anyone know why this is happening and hopefully have a solution?

Why does recursive Dispatch.main.async take longer and longer?
 
 
Q