Swift와 Xcode로 개발하는 동안 발생하는 문제를 해결하기 위해 Breakpoint는 필수적인 도구입니다. WWDC24의 “Run, Break, Inspect: Explore effective debugging in LLDB” 세션에서 소개된 Breakpoint의 동작 방식과 고급 기능에 대해 심층적으로 알아보겠습니다.
Breakpoint의 기본 메커니즘 이해하기
단일 코드에 여러 Breakpoint가 생성되는 이유
Button("Hello, world!") {
someMethod()
}
위 코드에서 Button 생성자에 Breakpoint를 설정했을 때, 흥미로운 현상이 발생합니다. 코드 한 곳에 Breakpoint를 설정했는데, 실행 시 여러 다른 위치에서 프로그램이 중단됩니다.
이러한 현상은 Breakpoint Navigator에서 확인할 수 있습니다. 하나의 Breakpoint를 설정했음에도 여러 개의 Breakpoint 항목이 표시됩니다. 이는 Xcode가 서로 다른 코드 경로를 통해 동일한 Breakpoint에 도달할 수 있는 모든 경우를 추적하기 때문입니다.
Button 예제에서 구체적으로:
- Breakpoint 1.1: Button이 생성되는 시점
- Breakpoint 1.2: Button 생성자의 trailing closure가 실행되는 시점
복잡한 Button에서의 Breakpoint
action과 label이 모두 있는 Button을 생성하는 경우:
@State private var isAddedToWatchLater = false
Button(action: { self.isAddedToWatchLater.toggle() }) {
Text(isAddedToWatchLater ? "Added to Watch Later" : "Add to Watch Later")
}
이 코드에 Breakpoint를 설정하면 Xcode는 세 개의 서로 다른 Breakpoint를 생성합니다:
- Breakpoint 1.1: Button의 생성자가 호출될 때
- Breakpoint 1.2: Button의 action closure가 실행될 때
- Breakpoint 1.3: Button의 trailing closure(UI 표시 부분)가 실행될 때
실제 실행 순서는 1.1 → 1.3 → 1.2로, 버튼이 생성되고, UI가 렌더링된 후, 사용자 액션에 따라 action closure가 실행됩니다.
LLDB에서 Breakpoint 관리하기
Breakpoint 목록 확인
LLDB 콘솔에서 더 자세한 정보를 확인할 수 있습니다:
(lldb) breakpoint list
이 명령어는 현재 설정된 모든 Breakpoint의 상세 정보(ID, 위치, 히트 카운트 등)를 표시합니다. 이를 통해 Navigator에서 보이는 것보다 더 많은 정보를 얻을 수 있습니다.
Breakpoint 비활성화
특정 경로의 Breakpoint를 비활성화하는 방법:
- Navigator에서 해당 Breakpoint의 파란색 점을 클릭하여 흐린 파란색으로 변경
- 또는 Breakpoint를 우클릭하고 ‘Disable Breakpoint Location’ 선택
- LLDB에서는
breakpoint disable <ID>
명령어 사용
Swift Error Breakpoint: 오류 지점 빠르게 찾기
에러 처리 코드에서 실제 오류 발생 지점을 찾는 것은 어려울 수 있습니다. Swift Error Breakpoint는 이런 상황에서 매우 유용합니다.
실제 사용 예시
JSON 파싱 예제를 살펴보겠습니다:
let jsonData = self.jsonString.data(using: .utf8)!
do {
let videos = try decoder.decode([Video].self, from: jsonData)
for video in videos {
print(video.title, video.description)
}
} catch {
// error 처리가 없음
}
만약 JSON 데이터 중 하나의 객체에 imageName
대신 imag
와 같은 오타가 있다면:
- 일반적인 접근: 파싱 로직에 Breakpoint를 설정하고 모든 객체를 하나씩 확인
- 향상된 접근: Swift Error Breakpoint 사용
Swift Error Breakpoint 설정 방법
- Breakpoint Navigator에서 좌측 하단의 ‘+’ 버튼 클릭
- ‘Swift Error Breakpoint’ 선택
- 프로그램 실행
이제 Swift 에러가 처음 발생하는 지점에서 프로그램이 자동으로 중단됩니다. LLDB를 사용하여 해당 시점의 상태(예: 오류가 발생한 객체의 ID)를 검사할 수 있습니다.
(lldb) po error
(lldb) po id
이를 통해 오류가 발생한 정확한 객체와, 문제가 있는 부분을 빠르게 식별할 수 있습니다.
High-firing Breakpoint 관리 기술
반복문이나 자주 호출되는 함수에 설정된 Breakpoint는 프로그램을 과도하게 중단시켜 디버깅 효율성을 저하시킬 수 있습니다. WWDC에서는 이러한 “High-firing Breakpoint”를 효과적으로 관리하는 세 가지 기술을 소개했습니다.
1. Breakpoint Conditions
특정 조건이 충족될 때만 Breakpoint가 활성화되도록 설정:
for video in videos {
print(video.title, video.description) // Breakpoint 위치
}
이 코드에서 description
의 길이가 30자를 초과하는 경우에만 중단하고 싶다면:
- Breakpoint를 우클릭하고 ‘Edit Breakpoint’ 선택
- Condition 필드에
video.description.count > 30
입력
이제 조건이 true인 경우에만 프로그램이 중단됩니다.
2. Breakpoint Action과 임시 Breakpoint (tbreak)
특정 함수 호출 후에만 Breakpoint를 활성화하는 고급 기법:
for video in videos {
if video.hasRemoteMedia {
video.loadRemoteMedia() // 첫 번째 Breakpoint 위치
}
processSomething() // 두 번째 Breakpoint 위치를 조건부로 활성화하고 싶음
}
loadRemoteMedia()
가 호출된 경우에만 processSomething()
에서 중단하려면:
loadRemoteMedia()
함수에 Breakpoint 설정- ‘Edit Breakpoint’ → ‘Add Action’ → ‘Debugger Command’ 선택
tbreak processSomething
또는tbreak {filename}:{linenumber}
입력
여기서 tbreak
는 “temporary breakpoint”의 약자로, 해당 위치에서 한 번만 프로그램을 중단시킨 후 자동으로 제거됩니다. LLDB는 이를 “one-shot breakpoint”라고 표시합니다.
임시 Breakpoint는 LLDB에서 직접 생성할 수도 있습니다:
(lldb) tbreak processSomething
3. Breakpoint Ignore Count
Breakpoint가 특정 횟수 동안 무시되고, 그 이후에만 활성화되도록 설정:
- Breakpoint를 우클릭하고 ‘Edit Breakpoint’ 선택
- ‘Ignore’ 필드에 원하는 횟수 입력
이 설정은 처음 N번의 Breakpoint 히트를 무시하고, N+1번째부터 프로그램을 중단시킵니다. 특정 반복에서만 검사하고 싶을 때 유용합니다.
실전 디버깅 워크플로우 최적화
위에서 배운 기술들을 조합하여 효율적인 디버깅 워크플로우를 구성할 수 있습니다:
- 문제 식별: Swift Error Breakpoint를 사용하여 오류 발생 지점 찾기
- 상세 분석: 조건부 Breakpoint를 사용하여 특정 상황에서만 코드 검사
- 흐름 추적: 임시 Breakpoint(tbreak)를 사용하여 특정 함수 호출 간의 관계 분석
- 반복 문제 해결: Ignore Count를 사용하여 N번째 반복에서만 검사
이러한 기술들을 상황에 맞게 적용하면 복잡한 문제도 더 효율적으로 해결할 수 있습니다.
결론
Breakpoint는 단순히 코드 실행을 중단시키는 도구를 넘어, 다양한 기능을 제공하는 강력한 디버깅 도구입니다. WWDC24에서 소개된 기술들을 활용하면 더 효율적이고 정확한 디버깅이 가능해집니다. 특히 tbreak
와 같은 일회성 Breakpoint는 특정 상황만 빠르게 확인하고 싶을 때 매우 유용합니다.
이러한 고급 Breakpoint 기술들을 마스터하면 복잡한 문제도 더 체계적으로 접근하고 해결할 수 있으며, 궁극적으로 개발 생산성 향상에 크게 기여할 수 있습니다.
출처
- WWDC24 세션: “Run, Break, Inspect: Explore effective debugging in LLDB”