CPU use increases over time with simple animation

I created a simple animation of a circle that changes sizes. The circle pulses like a heartbeat in the center of the screen. My expectation was for the CPU use to be very low, but that is not the case. In addition, even if the CPU use isn't as low as I would expect, I did not expect the CPU use to increase over time because nothing else is happening in the app. Here is the code:

import SwiftUI

@main
struct TestApp: App {

  var body: some Scene {
    WindowGroup {
      SplashScreenView()
    }
  }

}
import SwiftUI

struct SplashScreenView: View {

  var body: some View {
    ZStack {
      SplashNucleusView(minSize: 50, maxSize: 100)
    }
  }

}
import SwiftUI

struct SplashNucleusView: View {
  let minSize: Double
  let maxSize: Double

  @State private var nucleusColor: Color = .primary
  @State private var nucleusRadius: Double = 10
  @State private var nucleusOpacity: Double = 1.0

  private var nucleusAnimation: Animation {
    .easeInOut(duration: 0.25)
    .repeatForever(autoreverses: true)
  }

  let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()

  var body: some View {
    Circle()
      .fill(nucleusColor)
      .frame(width: nucleusRadius)
      .opacity(nucleusOpacity)
      .onReceive(timer) { _ in
        withAnimation(nucleusAnimation) {
          nucleusRadius = Double.random(in: minSize...maxSize)
        }
      }
  }

}

This is how the animation looks:

The animation is snappy until the CPU use reaches 95%, at which point there is visible stuttering. Here is how the CPU looks when the animation duration value is 0.5 seconds and the timer publishing interval is 3 seconds:

Changing the animation duration value to 0.25 seconds and the timer publishing interval to 0.5 seconds changes the CPU use as follows:

The complete view has many other moving parts, which make the issue much worse. The issue is evident with only the circle view. I spent hours working with the debugger, reading about animations, and testing new approaches, but the result is always the same.

Why is this happening?

The problem is repeatForever. Please see my post and answer on Stack Overflow for more information.

For reference, the onRecieve modifier is executing every 3 seconds when the timer publishing interval is set to 3 seconds:

      .onReceive(timer) { _ in
        print("got here: \(Date())")
        withAnimation(nucleusAnimation) {
          print("animation got here: \(Date())")
          nucleusRadius = Double.random(in: minSize...maxSize)
        }
      }
got here: 2024-10-27 14:05:58 +0000
animation got here: 2024-10-27 14:05:58 +0000
got here: 2024-10-27 14:06:01 +0000
animation got here: 2024-10-27 14:06:01 +0000
got here: 2024-10-27 14:06:04 +0000
animation got here: 2024-10-27 14:06:04 +0000
got here: 2024-10-27 14:06:07 +0000
animation got here: 2024-10-27 14:06:07 +0000
got here: 2024-10-27 14:06:10 +0000
animation got here: 2024-10-27 14:06:10 +0000

In addition, changing the timer instantiaton as follows, which appears to be more correct, did not change the CPU use:

    .onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { output in
      withAnimation(nucleusAnimation) {
        nucleusRadius = Double.random(in: minSize...maxSize)
      }
    }
Accepted Answer

The problem is repeatForever. Please see my post and answer on Stack Overflow for more information.

CPU use increases over time with simple animation
 
 
Q