@ViewBuilder 완전 정리 — 왜 필요한가?SwiftUI로 UI를 작성하다 보면 여러 개의 뷰를 나열하는 상황이 많다.
하지만 SwiftUI의 함수나 body는 단 하나의 View만 반환해야 한다.
그럼에도 여러 개의 뷰를 쌓을 수 있는 이유가 뭘까? 바로 @ViewBuilder 덕분이다.
@ViewBuilder란?
@ViewBuilder는 여러 개의 뷰를 하나의 View로 조합해주는 Function Builder이다.
쉽게 말해, 여러 View를 선언적으로 나열하면 Swift가 알아서 하나의 View 트리로 합쳐준다.
이 덕분에 body나 커스텀 컴포넌트에서 뷰를 자연스럽게 쌓을 수 있다.
SwiftUI에서 함수나 프로퍼티는 some View → 단일 View만 반환 가능하다.
func myView() -> some View {
Text("Hello")
Text("World") // 오류 발생
}
그럼 이렇게 여러 View를 어떻게 쌓을 수 있을까?
@ViewBuilder가 이 문제를 해결해준다.
@ViewBuilder
func myView() -> some View {
Text("Hello")
Text("World") // 자동으로 TupleView로 묶임
}
Swift는 내부적으로 이 코드를 TupleView<(Text, Text)> 형태로 변환해준다.
@ViewBuilder를 쓰다보면 계속해서 아래와 같은 식으로 꼬리에 꼬리를 물면서 하나로 생성이 된다.
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<Text, _FrameLayout>, _BackgroundStyleModifier<AnyGradient>>, _EnvironmentKeyWritingModifier<Optional<Color>>>, _EnvironmentKeyWritingModifier<Optional<Font>>>, _ClipEffect<RoundedRectangle>>
@ViewBuilder는 Swift의 Function Builder 기능을 사용한다.
컴파일러가 빌더 안의 여러 반환값을 하나로 합쳐주는 문법적 도우미다.
덕분에 다음과 같은 일이 가능해진다.
if/else, switch, ForEach 같은 제어문 사용즉, SwiftUI의 선언적 UI 패러다임을 가능하게 하는 핵심 문법이다.
@ViewBuilder
func myView() -> some View {
Text("Hello")
Text("World")
}
자동으로 하나의 View로 합쳐지기 때문에 별도의 컨테이너를 명시하지 않아도 된다.
@ViewBuilder
func greetingView(isMorning: Bool) -> some View {
if isMorning {
Text("Good Morning")
} else {
Text("Good Evening")
}
}
빌더 내부에서 조건문을 자유롭게 쓸 수 있다.
@ViewBuilder
func listView(items: [String]) -> some View {
ForEach(items, id: \.self) { item in
Text(item)
}
}
여러 개의 뷰를 동적으로 생성할 때도 유용하다.
@ViewBuilder는 클로저 형태로 View를 받아야 하는 커스텀 컴포넌트에서 특히 중요하다.
struct MyCard<Content: View>: View {
let title: String
let content: Content
init(title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
var body: some View {
VStack {
Text(title)
.font(.headline)
content
}
}
}
struct ContentView: View {
var body: some View {
MyCard(title: "SwiftUI") {
Text("ViewBuilder Example")
Text("Hello World")
}
}
}
body는 왜 여러 View를 쌓을 수 있을까?하나 의문이 생긴다. body에는 @ViewBuilder를 명시하지 않았는데 왜 여러 View를 쌓을 수 있을까?
정답은, SwiftUI가 body 프로퍼티에 암묵적으로 @ViewBuilder를 적용하기 때문이다.
즉, 다음 두 코드는 동일하게 작동한다.
// SwiftUI 내부에서 암묵적으로 이렇게 처리됨
@ViewBuilder
var body: some View {
Text("Hello")
Text("World")
}
| 개념 | 설명 |
|---|---|
@ViewBuilder | 여러 View를 하나의 View 트리로 조합하는 SwiftUI 전용 Function Builder |
| 필요성 | some View가 단일 View만 반환할 수 있기 때문 |
| 특징 | if/else, ForEach 등 제어문도 사용 가능 |
| body | 암묵적으로 @ViewBuilder 적용 |