[Xcode] Instruments 로 Hang 개선하기
WWDC 23 > Analyze hanges with Instruments 를 기반하고 있습니다.
(40분 쯤 되는데 너무 재밌고 유용함. 강추)
# Hang
hang 은 delay 를 의미한다고 생각하면 됩니다.
Xcode Instruments 에서 녹화버튼을 꾹 누르고 Recording Options 에 가보면
Hang, MicroHang 등 애플이 몇초 기반으로 정의해뒀는 지 볼 수 있고
프로파일링할때 어디까지 리포트되게 할 건지 설정가능합니다.
# Hang 만들어보기
Hang 을 유발할 코드를 만들어봅시다.
struct ContentView: View {
@State private var showImagePicker = false
var body: some View {
Button(action: {
showImagePicker = true
}, label: {
Text("이미지 피커")
})
.sheet(isPresented: $showImagePicker) {
ImagePicker()
}
}
}
struct ImagePicker: View {
var body: some View {
ScrollView {
HStack {
ForEach(0..<1000) { i in
DummyImageView()
}
}
}
}
struct DummyImageView: View {
let potatoImageUrlString = "https://i.namu.wiki/i/xqZXxdDm2FGg7jdsA3VcmR2RMyn8LSzyxPXj1lHcQC_Qhy1bBSxNS5sZcXIG5bQpMVxzG4YMtArPkjkAWFDN0BdGoXhCUluNe863yLGQ3pbuWjSw1nvBEpMF5xvd8BbDe98PDsGla2OWognYzwvDlg.webp"
var body: some View {
AsyncImage(url: URL(string: potatoImageUrlString)) { image in
image.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 100, height: 100)
}
}
이미지 피커 버튼을 누르면 hang 이 발생합니다.
# Instruments 와 함께 Hang 해결하기
Profile 버튼을 눌러서 Instruments > Time Profiler 를 열어줍니다.
SwiftUI 앱이므로 같이 보기 좋은 도구도 추가해줍니다.
View Body 를 추가해줍니다.
그리고 레코딩 버튼을 눌러줍니다.
Severe Hang 발생함을 볼 수 있습니다.
멈춤을 누르고 옵션 + 우클릭해서 Severe Hange 구간을 확대해줍니다.
My App > Main Thread 를 열어봅니다.
두가지 타입의 Hang 중에서 Busy Main Thread 임을 먼저 확인합니다.
또한 MainThread 에 가보면 많은 작업들이 수행되고 있고
(+ Hide System Libraries 를 하면 System Call Stack 을 숨길 수 있습니다.)
SwiftUI > View Body 로 가보면
AsyncImage body count가 매우 많이 호출되고 있음을 알 수 있습니다.
Busy Main Thread 는 한 작업이 오래걸리는 게 아니라 여러 작업이 많이 발생해서 임을
인지합니다. (Too Long 이 아니라 Too Often)
AsyncImage 가 많이 호출됨이 원인임을 알았으니 코드를 수정해줍니다.
LazyHStack 을 안해줬구나.. 깨닫고 코드를 수정해줍니다. (살짝 억지이긴 한데..-_- 예제니까..)
struct ImagePicker: View {
var body: some View {
ScrollView {
LazyHStack {
ForEach(0..<1000) { i in
DummyImageView()
}
}
}
}
다시 프로파일링을 해보면 여전히 body count 가 그대로인 것을 볼 수 있습니다.
ScrollView direction 을 빼먹었음을 깨닫고 코드를 수정해줍니다.
struct ImagePicker: View {
var body: some View {
ScrollView(.horizontal) {
LazyHStack {
ForEach(0..<1000) { i in
DummyImageView()
}
}
}
}
다시 프로파일링을 해보면
SwiftUI body count도 줄고
Hang 도 없어진 것을 볼 수 있습니다.
+ WWDC 후반부에는 Task 관련 Hang 개선도 나오니 참고..!
[ 더 보면 좋을 것 ]
https://developer.apple.com/wwdc22/10082
https://developer.apple.com/documentation/xcode/understanding-hangs-in-your-app