You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
개인적으로 만들고 있는 명상 앱 운기조식에는 Metal을 통한 애니메이션 구현 부분이 있습니다. Instruments를 돌렸더니 CoreAnimation쪽에서 빨간색으로 아래와 같이 난리가 났었습니다🤯
아니 Animation 적용하는 건 아는데 Core Animation은 뭐람이라고 가볍게 생각했지만 가볍지 않는 주제여서 미뤘다가 최근 다시 운기조식을 2.0.0을 준비하면서 이 부분을 해결해야 할 때가 왔습니다.
근데 해결되었다?
3개월쯤 흘러 다시 운기조식을 돌려보았는데 CoreAnimation쪽 문제가 사라져있습니다?
조건을 맞춰주기 위해 그때 빌드했던 iPhone 15 pro simulator로 돌려보았지만 여전히 동일하게 commit들이 사라져있었습니다.
그럼 글을 마치겠습니다. 읽어주셔서 감사합니다.
Core Animation Commits
라고 끝나면 Core Animation Commits이 또 발생할 수 있으니... Core Animation Commits에 대해 알아보겠습니다.
Core Animation Commits
SwiftUI는 성능을 높이기 위해 Metal을 바로 사용할 수 있지만, 대부분의 경우 렌더링을 위해 Core Animation을 선호합니다. 이는 우리가 Instruments에서 제공하는 내장된 Core Animation 성능 분석 도구를 자동으로 사용할 수 있음을 의미하며, 여기에는 비용이 많이 드는(commit이 무거운) 작업을 감지하는 기능도 포함됩니다.
Core Animation은 여러 변경 사항을 트랜잭션(transaction)이라고 불리는 단일 그룹으로 묶어 처리할 때 가장 효율적으로 작동합니다. 우리는 여러 작업을 하나의 트랜잭션에 쌓아 올리고, Core Animation에 렌더링 작업을 진행하도록 요청합니다. 이를 트랜잭션 커밋(commit)이라고 부릅니다.
따라서 Instruments에서 비용이 많이 드는 Core Animation 커밋을 표시할 때, 이는 실제로 SwiftUI가 화면의 픽셀을 다시 그려야 했던 횟수를 보여줍니다. 이론적으로 이러한 재렌더링은 앱 상태의 변화로 인해 새로운 뷰 계층 구조(view hierarchy)가 필요한 경우에만 발생해야 합니다. SwiftUI는 body 프로퍼티의 새로운 출력과 이전 출력을 비교해 변경 여부를 판단할 수 있기 때문입니다.
ComplexViewWithAnimation 뷰에 있는 Cell의 개수를 늘렸는데, 이런 경우에는 CoreAnimationCommit에 대한 비용도 증가했지만, 메인쓰레드에 부담이 가서 hang이 각 count마다 hang이 10초 정도 발생하였습니다.
structTestView:View{@Stateprivatevarcount:Int=0privatelettimeInterval:Double=0.001varbody:someView{ZStack{ExpensiveView()ComplexViewWithAnimation()Text("\(count)")}.onAppear{let _ =Timer.scheduledTimer(withTimeInterval: timeInterval, repeats:true){ _ in
count +=1}}}}
// MARK: 변경 부분
// Canvas 컴포넌트의 경우 뷰를 그리는데 계산 비용이 큰 컴포넌트라고 합니다.
structExpensiveView:View{varbody:someView{Canvas{ context, size infor_in0..<5000{letrect=CGRect(
x:Double.random(in:0...size.width),
y:Double.random(in:0...size.height),
width:Double.random(in:10...50),
height:Double.random(in:10...50))
context.fill(Path(ellipseIn: rect), with:.color(.blue))}}.frame(width:300, height:300).background(Color.gray.opacity(0.1))}}structComplexViewWithAnimation:View{@StateprivatevarisAnimating=false@Stateprivatevartimer=Timer.publish(every:0.001, on:.main, in:.common).autoconnect()varbody:someView{VStack{
// MARK: 변경 부분
ForEach(0..<100){ outerIndex inHStack{ForEach(0..<100){ innerIndex inZStack{Circle().fill(isAnimating ?Color.blue.opacity(0.3):Color.green.opacity(0.3)).frame(width: isAnimating ?60:50, height: isAnimating ?60:50).animation(.easeInOut(duration:0.3), value: isAnimating)Text("\(outerIndex), \(innerIndex)").font(.caption).foregroundColor(isAnimating ?.yellow :.white).animation(.easeInOut(duration:0.3), value: isAnimating)RoundedRectangle(cornerRadius:8).stroke(isAnimating ?Color.red :Color.purple, lineWidth:1).frame(width: isAnimating ?70:60, height: isAnimating ?70:60).animation(.easeInOut(duration:0.3), value: isAnimating)}}}}}.padding().onReceive(timer){ _ in
isAnimating.toggle()}}}
2025-01-23.1.26.54.mov
hang이 발생하는 이유
너무 많은 연산(예: 레이아웃 재계산, 상태 변경)이 메인 쓰레드에서 발생하면 Core Animation 커밋 단계에 필요한 시간을 확보할 수 없습니다. 위 코드에서 0.001초 단위에 빈번한 작업이 메인쓰레드를 차단해서 행이 발생했습니다.
이렇게 애니메이션을 자주, 복잡한 계층 구조의 View를 계산하게 되면 프렘임드랍이 발생하므로 주의해야합니다.
정리
두서없이 이야기하고 테스트 위주의 결과를 보여드렸습니다. 사실 최악의 케이스에 대한 부분이나 명확하게 어떤 코드에서 이런 문제가 발생하는지에 대한 파악이 더 필요해보입니다. Core Animation Commit이 많이 발생하는 경우 다음의 개선을 시도해볼 수 있습니다.
복잡한 계층구조 또는 계산이 들어가는 화면을 너무 자주(0.016초 이하로) 새로 렌더하고 있지 않은지 확인합니다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Core Animation Commit 문제
개인적으로 만들고 있는 명상 앱 운기조식에는 Metal을 통한 애니메이션 구현 부분이 있습니다. Instruments를 돌렸더니 CoreAnimation쪽에서 빨간색으로 아래와 같이 난리가 났었습니다🤯
아니 Animation 적용하는 건 아는데 Core Animation은 뭐람이라고 가볍게 생각했지만 가볍지 않는 주제여서 미뤘다가 최근 다시 운기조식을 2.0.0을 준비하면서 이 부분을 해결해야 할 때가 왔습니다.
근데 해결되었다?
3개월쯤 흘러 다시 운기조식을 돌려보았는데 CoreAnimation쪽 문제가 사라져있습니다?
조건을 맞춰주기 위해 그때 빌드했던 iPhone 15 pro simulator로 돌려보았지만 여전히 동일하게 commit들이 사라져있었습니다.
그럼 글을 마치겠습니다. 읽어주셔서 감사합니다.
Core Animation Commits
라고 끝나면 Core Animation Commits이 또 발생할 수 있으니... Core Animation Commits에 대해 알아보겠습니다.
Core Animation Commits
SwiftUI는 성능을 높이기 위해 Metal을 바로 사용할 수 있지만, 대부분의 경우 렌더링을 위해 Core Animation을 선호합니다. 이는 우리가 Instruments에서 제공하는 내장된 Core Animation 성능 분석 도구를 자동으로 사용할 수 있음을 의미하며, 여기에는 비용이 많이 드는(commit이 무거운) 작업을 감지하는 기능도 포함됩니다.
Core Animation은 여러 변경 사항을 트랜잭션(transaction)이라고 불리는 단일 그룹으로 묶어 처리할 때 가장 효율적으로 작동합니다. 우리는 여러 작업을 하나의 트랜잭션에 쌓아 올리고, Core Animation에 렌더링 작업을 진행하도록 요청합니다. 이를 트랜잭션 커밋(commit)이라고 부릅니다.
따라서 Instruments에서 비용이 많이 드는 Core Animation 커밋을 표시할 때, 이는 실제로 SwiftUI가 화면의 픽셀을 다시 그려야 했던 횟수를 보여줍니다. 이론적으로 이러한 재렌더링은 앱 상태의 변화로 인해 새로운 뷰 계층 구조(view hierarchy)가 필요한 경우에만 발생해야 합니다. SwiftUI는
body
프로퍼티의 새로운 출력과 이전 출력을 비교해 변경 여부를 판단할 수 있기 때문입니다.출처: [Hacking with Swift](https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-instruments-to-profile-your-swiftui-code-and-identify-slow-layouts)
요약하자면
[정리] Core Animaion Commits에서 레드사인이 발생하는 경우!
바로 테스트
시간 간격을 다르게 한 Timer에 따라서 CoreAnimation Commit이 어떻게 변화하는지 보겠습니다.
아래 코드에서 timeInteval의 변화에 따른 Core Animation Commit에 대해 보겠습니다.
2025-01-22.10.18.45.mov
2025-01-22.10.19.44.mov
👀 레드사인이 없다.
시간이 0.0001초에 한번씩 body가 새로 그려지는데 CoreAnimation commit에 대한 레드사인이 뜨지 않고 있습니다.
Core Animation Commit이 뷰의 계층구조를 새롭게 그리는데, 자주 렌더하는 것만을 보여주는 것이 아니었습니다. Core Animation에 영향을 주는건 뷰의 그려지는 횟수, 그리고 뷰 계층 구조의 복잡도에 영향을 받습니다.
조금 더 계층구조를 복잡하게
계층구조를 조금 더 복잡하게 하고, 애니메이션도 추가했습니다. 그런데 아직도 레드사인이 나오지 않습니다. 이렇게 성능이 좋은데 레드사인이 나올정도면 심각한 것이겠죠…
2025-01-23.12.53.50.mov
ComplexViewWithAnimation
ComplexViewWithAnimation 뷰에 있는 Cell의 개수를 늘렸는데, 이런 경우에는 CoreAnimationCommit에 대한 비용도 증가했지만, 메인쓰레드에 부담이 가서 hang이 각 count마다 hang이 10초 정도 발생하였습니다.
2025-01-23.1.26.54.mov
hang이 발생하는 이유
너무 많은 연산(예: 레이아웃 재계산, 상태 변경)이 메인 쓰레드에서 발생하면 Core Animation 커밋 단계에 필요한 시간을 확보할 수 없습니다. 위 코드에서 0.001초 단위에 빈번한 작업이 메인쓰레드를 차단해서 행이 발생했습니다.
이렇게 애니메이션을 자주, 복잡한 계층 구조의 View를 계산하게 되면 프렘임드랍이 발생하므로 주의해야합니다.
정리
두서없이 이야기하고 테스트 위주의 결과를 보여드렸습니다. 사실 최악의 케이스에 대한 부분이나 명확하게 어떤 코드에서 이런 문제가 발생하는지에 대한 파악이 더 필요해보입니다. Core Animation Commit이 많이 발생하는 경우 다음의 개선을 시도해볼 수 있습니다.
References
How to use Instruments to profile your SwiftUI code and identify slow layouts - a free SwiftUI by Example tutorial
Xcode | Apple Developer Documentation
Documentation
Beta Was this translation helpful? Give feedback.
All reactions