При использовании следующего кода SwiftUI потребление ресурсов ЦП моим приложением достигает 55 %, когда приложение работает в XCode (симуляторе) с M1.
На настоящем iPhone загрузка процессора достигает 52%.
К вашему сведению: CircleProgess обновляется каждые 0,1 секунды.
Circle()
.trim(from: 0.0, to: circleProgress)
.stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
.fill(Color.pink.gradient)
.rotationEffect(Angle(degrees: 270.0))
.animation(.default, value: circleProgress)
.frame(width: 100, height: 100)
Я обнаружил, что высокая загрузка ЦП вызвана не только, но и главным образом строкой Color.pink.gradient.
Если я использую тот же код, но с Color.pink вместо Color.pink.gradient, загрузка ЦП в симуляторе XCode составит около 15%. На реальном устройстве, например. iPhone 12: загрузка процессора все еще до 35%
Вот воспроизводимый пример
struct ContentView: View {
@ObservedObject var someTimer = SomeTimer()
var body: some View {
AnimatedCircle(circleProgress: $someTimer.circleProgess, size: 100)
AnimatedCircle(circleProgress: $someTimer.circleProgess, size: 400)
Spacer()
Button(action: someTimer.start, label: {
Text("Start animation")
})
Spacer()
}
}
class SomeTimer : ObservableObject {
@Published var circleProgess = 1.0
func start() {
circleProgess = 1.0
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) {_ in
self.circleProgess -= 0.001
}
}
}
struct AnimatedCircle: View {
@Binding var circleProgress : Double
var size : Int
var body: some View {
Circle()
.trim(from: 0.0, to: CGFloat(circleProgress))
.stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
.fill(Color.pink.gradient)
//.fill(Color.pink)
.rotationEffect(Angle(degrees: 270.0))
.animation(.default, value: CGFloat(circleProgress))
.frame(width: CGFloat(size), height: CGFloat(size))
}
}
Существует огромная разница в потреблении процессора при запуске AnimatedCircle() с .fill(Color.pink.gradient) или с .fill(Color.pink)
Есть идеи, как я могу использовать эту анимацию с Color.pink.gradient и при этом поддерживать загрузку процессора намного ниже 55%?
Спасибо
Спасибо @Sweeper. Я добавил минимальный пример того, как это вообще реализовано в моем приложении. В реальном приложении кругПрогресс НЕ рассчитывается в самом таймере и останавливается через 1 минуту. Это всего лишь пример
Переключите ObservedObject на StateObject. StateObject предназначен для инициализации, а ObservedObject — для передачи.
Спасибо @loremipsum, я изменил его на StateObject, но загрузка процессора все еще составляет около 50%.
Используя ваш пример Timer
, я обнаружил, что приложение использовало около 47% ресурсов ЦП при работе на симуляторе iPhone 15 с iOS 17.5.
Он использует меньше процессора, если вы сначала закрашиваете круг, а затем применяете обрезанную фигуру в качестве маски:
Circle()
.fill(Color.pink.gradient)
.frame(width: CGFloat(size), height: CGFloat(size))
.mask {
Circle()
.inset(by: 10) // half the line width
.trim(from: 0.0, to: CGFloat(circleProgress))
.stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
.rotationEffect(Angle(degrees: 270.0))
.animation(.default, value: CGFloat(circleProgress))
}
В моем тесте в симуляторе использовалось всего около 8% ЦП.
СПАСИБО @Бензи Низ. Вы сделали мой день :-). Теперь приложение не потребляет даже 8% процессора. Я хотел бы оценить ваш ответ, но после вашей помощи моя репутация ниже процента процессора, на котором работает мое приложение :-D Но есть ли объяснение, почему круг в моем исходном примере работает так плохо по сравнению с вашим подходом?
@LetsBeHappy Рад, что смог помочь. Я предполагаю, что в исходной реализации градиент пересчитывался при каждом изменении, и это могло немного нагружать процессор. Кстати, даже с низкой репутацией вы сможете принять ответ, нажав галочку, если вы довольны тем, что это решает проблему. Однако вам, возможно, придется немного подождать, прежде чем это позволит вам.
Я принял ваш ответ. Не знал, что смогу ;-). Теперь я проверил приложение на своем реальном устройстве iPhone 12, и ваше решение лучше, но процессор в XCode все равно отображается до 26%.
@LetsBeHappy Вы используете отладочную сборку на реальном устройстве? Попробуйте изменить его на сборку Release (это можно сделать, отредактировав схему). Пс. Спасибо, что приняли ответ!
Да, я запускал приложение с отладочной сборкой, но релизная сборка не особо помогла :-(
«Я обнаружил, что высокая загрузка ЦП вызвана главным образом линией Color.pink.gradient». Как вы это узнали? Я очень сомневаюсь, что проблема именно в этом. Пожалуйста, покажите минимально воспроизводимый пример, включая то, как вы обновляете
circleProgess
, чтобы другие люди могли самостоятельно выяснить, в чем проблема, а не просто предполагать, что вы правы.