๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

iOS/SwiftUI

SwiftUI) @ViewBuilder์™€ @resultBuilder

๋ฐ˜์‘ํ˜•

๐ŸŒˆ @ViewBuilder ๋ž€ ?

: SwiftUI์—์„œ ์—ฌ๋Ÿฌ View๋ฅผ ๊ทธ๋ฃนํ™”ํ•ด์„œ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํŠน๋ณ„ํ•œ ๋นŒ๋” ๋ฌธ๋ฒ•. 

๋ณดํ†ต Swift ํ•จ์ˆ˜๋Š” return์— ํ•˜๋‚˜์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ, ViewBuilder๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์ˆ˜์˜ View๋ฅผ ์„ ์–ธ์‹์œผ๋กœ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ.

 

 

- ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ 

struct MyView: View {
    var body: some View {
        VStack {
            Text("Hello")
            Text("World")
        }
    }
}

-> VStack ์˜ trailing closure๋Š” ViewBuilder๋กœ ์ •์˜๋œ ํด๋กœ์ € ์ด๊ธฐ ๋•Œ๋ฌธ์— Text๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋‚˜์—ด ํ•  ์ˆ˜ ์žˆ์Œ

 

 

โœ… ViewBuilder๊ฐ€ ์—†์œผ๋ฉด?

func makeView() -> some View {
    // ์ด๋ ‡๊ฒŒ๋Š” ์•ˆ๋จ (์ปดํŒŒ์ผ ์—๋Ÿฌ)
    Text("Hello")
    Text("World")
}

 

Swift๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•˜๋‚˜์˜ View๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ,

ViewBuilder๋ฅผ ์“ฐ๋ฉด ์—ฌ๋Ÿฌ View๋ฅผ ๋งˆ์น˜ ํ•˜๋‚˜์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ฌถ์–ด์ค„ ์ˆ˜ ์žˆ์Œ

 

โœ… ViewBuilder๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ

@ViewBuilder
func greetingView() -> some View {
    Text("Hello")
    Text("World")
}
  • @ViewBuilder๋ฅผ ๋ถ™์ด๋ฉด ์—ฌ๋Ÿฌ View๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ฐ€๋Šฅํ•ด์ ธ.
  • Swift๊ฐ€ ์ž๋™์œผ๋กœ ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌํ•ด์คŒ.

 

โœ… ViewBuilder์˜ ์žฅ์ 

 

  • SwiftUI์˜ ์„ ์–ธ์  UI ๋ฌธ๋ฒ•์„ ๊น”๋”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
  • ๋ทฐ ์กฐํ•ฉ ์‹œ ๊ฐ€๋…์„ฑ์ด ๋†’์•„์ง
  • ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ˜๋ณต๋ฌธ์„ ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅ
VStack {
    if isLoggedIn {
        Text("Welcome!")
    } else {
        Text("Please log in.")
    }
}

-> ์ด๋Ÿฐ ์กฐ๊ฑด ๋ถ„๊ธฐ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์Œ.

 

 

์‚ฌ์‹ค @ViewBuilder๋Š” Swift์˜ @resultBuilder ๋ฌธ๋ฒ•์„ ํ™œ์šฉํ•ด์„œ ๋งŒ๋“  '์ปค์Šคํ…€ ๋นŒ๋”' ์ค‘ ํ•˜๋‚˜
SwiftUI๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋ ค๋ฉด @resultBuilder์˜ ๊ตฌ์กฐ๋ฅผ ์•„๋Š”๊ฒŒ ์ข‹์Œ.

 

 

โœ… @resultBuilder๋ž€?

- ๋‹ค์–‘ํ•œ ํ‘œํ˜„์‹๋“ค์„ ํ•˜๋‚˜์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋กœ ํ•ฉ์ณ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ Swift์˜ ํŠน๋ณ„ํ•œ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ

 

  • "์—ฌ๋Ÿฌ ์ค„์˜ ์ฝ”๋“œ๋ฅผ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ํ•ฉ์ณ์ฃผ๋Š” ๊ทœ์น™"์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ.
  • SwiftUI์˜ ViewBuilder, SwiftRegexBuilder, StringBuilder ๋“ฑ์— ์‚ฌ์šฉ๋จ

 

โœ… ๊ธฐ๋ณธ ๊ตฌ์กฐ

@resultBuilder๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด์„ํ• ์ง€ ์•Œ๋ ค์ฃผ๋Š” "์ปดํŒŒ์ผ๋Ÿฌ ๊ฐ€์ด๋“œ" ๊ฐ™์€ ์—ญํ• ์„ ํ•ด.

@resultBuilder
struct ArrayBuilder {
    static func buildBlock(_ components: Int...) -> [Int] {
        return components
    }
}

@ArrayBuilder
func makeArray() -> [Int] {
    1
    2
    3
}

// ๊ฒฐ๊ณผ: [1, 2, 3]

- buildBlock ๋ฉ”์„œ๋“œ: ์—ฌ๋Ÿฌ ํ‘œํ˜„์‹์„ ๋ฌถ์–ด์ฃผ๋Š” ์—ญํ• 

 

โœ… ํ•„์ˆ˜ ๋ฉ”์„œ๋“œ

๋ฉ”์„œ๋“œ ์—ญํ• 
buildBlock ์—ฌ๋Ÿฌ ํ‘œํ˜„์‹์„ ํ•˜๋‚˜๋กœ ๋ฌถ์Œ
buildOptional if ๋ฌธ์—์„œ ์‚ฌ์šฉ, nil์ผ ์ˆ˜๋„ ์žˆ์Œ
buildEither(first:) / buildEither(second:) if-else์—์„œ ๋ถ„๊ธฐ ์„ ํƒ
buildArray ForEach ๊ฐ™์€ ๋ฐ˜๋ณต๋ฌธ ์ง€์›
buildLimitedAvailability @available ๊ฐ™์€ ์กฐ๊ฑด ์ฒ˜๋ฆฌ

 

๐Ÿ” ์ž์„ธํžˆ ๋ณด๊ธฐ

1. buildBlock 

static func buildBlock(_ components: View...) -> View { }

- VStack { Text("a") ; Text("b") } ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ View๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์„ ๋•Œ ์‚ฌ์šฉ

 

 

2. buildEither

static func buildEither(first: View) -> View { }
static func buildEither(second: View) -> View { }

- if, else ๋ฌธ์„ ์‚ฌ์šฉํ•  ๋•Œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ

 

 

3. buildOptional

static func buildOptional(_ component: View?) -> View { }

- if ๋‹จ๋…๋ฌธ์—์„œ optional ๊ฐ’์„ ์ฒ˜๋ฆฌ ํ•  ๋•Œ ํ˜ธ์ถœ

 

 

4. buildArray

static func buildArray(_ components: [View]) -> View { }

- ForEach ๊ฐ™์€ ๋ฐ˜๋ณต๋ฌธ ์ฒ˜๋ฆฌํ•  ๋•Œ ํ˜ธ์ถœ

 

โœ… SwiftUI์˜ ViewBuilder ๋‚ด๋ถ€

@resultBuilder
public struct ViewBuilder {
    public static func buildBlock(_ components: some View...) -> some View { ... }
    public static func buildOptional(_ component: some View?) -> some View { ... }
    public static func buildEither(first component: some View) -> some View { ... }
    public static func buildEither(second component: some View) -> some View { ... }
    public static func buildArray(_ components: [some View]) -> some View { ... }
}

 

๐Ÿ‘‰ ์ฆ‰, SwiftUI์—์„œ

VStack {
    if isOn { Text("ON") }
    else { Text("OFF") }
}

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ์‹ค์ œ๋กœ๋Š” ViewBuilder.buildEither๊ฐ€ ํ˜ธ์ถœ ๋˜๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋‹ค ์กฐ๋ฆฝํ•ด์ฃผ๋Š” ๊ฒƒ !

 

 

๋‹ค์‹œ ViewBuilder๋กœ ๋Œ์•„์™€์„œ, 
๊ทธ๋Ÿผ ViewBuilder๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ ๊ฒฝ์šฐ๋Š” ์–ธ์ œ์ผ๊นŒ ?

 

 

โœ… ViewBuilder๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ ๊ฒฝ์šฐ

1. ์—ฌ๋Ÿฌ View๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปค์Šคํ…€ ํ•จ์ˆ˜๋‚˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ 

@ViewBuilder
func CustomSection(title: String) -> some View {
    Text(title)
        .font(.headline)
    Divider()
}

๐Ÿ‘‰ @ViewBuilder ๋•๋ถ„์— Text์™€ Divider๋ฅผ ํ•จ์ˆ˜์—์„œ ์—ฌ๋Ÿฌ ์ค„๋กœ ๋ฐ”๋กœ ๋ฆฌํ„ด ๊ฐ€๋Šฅ.

 

2. ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌํ„ดํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ 

- ํŠนํžˆ SwiftUI์—์„œ๋Š” Slot API ๊ฐ™์€ ๋””์ž์ธ์„ ๊ตฌํ˜„ํ•  ๋•Œ ViewBuilder๊ฐ€ ์ •๋ง ์œ ์šฉํ•ด.

* Slot API๋Š” "๋‚ด๊ฐ€ ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ ์•ˆ์—, ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด '์›ํ•˜๋Š” View'๋ฅผ ๊ฝ‚์•„ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“  ๊ตฌ์กฐ"

struct CustomCard<Content: View>: View {
    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        VStack {
            content()
        }
        .padding()
        .background(Color.gray.opacity(0.2))
        .cornerRadius(12)
    }
}

 

๐Ÿ‘‰ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค๋ฉด ๋‚ด๋ถ€์— ์›ํ•˜๋Š” View๋ฅผ ๋งˆ์Œ๋Œ€๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ์Œ.

CustomCard {
    Text("Hello")
    Image(systemName: "star")
}

์ด๊ฒŒ VStack { }์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋Š” ์›๋ฆฌ.
(์‚ฌ์‹ค VStack๋„ ์ด๋Ÿฐ ์‹์œผ๋กœ ViewBuilder๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์Œ)

 

โœ… ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ ์ถ”๊ฐ€ ์˜ˆ์‹œ

 

1) ๊ทธ๋ƒฅ ์ผ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ

struct BasicCard: View {
    var body: some View {
        VStack {
            Text("Title")
            Text("Content")
        }
    }
}

๐Ÿ‘‰ ์ด๊ฑด ๊ณ ์ •๋œ ๋ทฐ์•ผ. ํ•ญ์ƒ "Title" + "Content"๋งŒ ๋ณด์—ฌ์ค˜.
๋‹ค๋ฅธ ํ™”๋ฉด์—์„œ ์žฌํ™œ์šฉํ•˜๊ธฐ์—” ๋”ฑ ์ด๊ฑฐ๋ฐ–์— ๋ชป ๋ณด์—ฌ์คŒ.

 

2) Slot API๋ฅผ ์ ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ - ์œ„์˜ ์ฒซ๋ฒˆ์งธ ์ฝ”๋“œ๋ธ”๋Ÿญ 

 

  • content: () -> Content → ๐Ÿ’ก ๋‚ด๊ฐ€ View๋ฅผ "์Šฌ๋กฏ์ฒ˜๋Ÿผ" ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ์Œ
  • @ViewBuilder → ์—ฌ๋Ÿฌ View๋ฅผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ์Œ
CustomCard {
    Text("์ด๊ฑด ๋‚ด ์นด๋“œ ์ œ๋ชฉ")
        .font(.headline)
    Text("์ด๊ฑด ๋‚ด ์นด๋“œ ๋‚ด์šฉ")
        .font(.subheadline)
    Image(systemName: "star.fill")
        .foregroundColor(.yellow)
}

 

๐Ÿ‘‰ ๊ฒฐ๊ณผ:

  • CustomCard๋ผ๋Š” "ํ‹€"์€ ์žฌ์‚ฌ์šฉํ•˜๊ณ 
  • ์•ˆ์— ๋“ค์–ด๊ฐ€๋Š” ๋‚ด์šฉ์€ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ
  • ์ฆ‰, ๋‚ด๊ฐ€ ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ์˜ ๋ผˆ๋Œ€๋Š” ์œ ์ง€ํ•˜๊ณ , ๋‚ด๋ถ€๋Š” ์œ ์—ฐํ•˜๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅํ•ด์ง !

 

 

 

3. ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ˜๋ณต๋ฌธ์ด ๋“ค์–ด๊ฐ€๋Š” ๋ณต์žกํ•œ View ์กฐ๋ฆฝ ํ•จ์ˆ˜ ๋งŒ๋“ค ๋•Œ 

@ViewBuilder
func StatusView(isActive: Bool) -> some View {
    if isActive {
        Text("Active")
            .foregroundColor(.green)
    } else {
        Text("Inactive")
            .foregroundColor(.red)
    }
}

๐Ÿ‘‰ if-else๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ž‘๋™ํ•˜๋Š” ์ด์œ ๋Š” ViewBuilder๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ buildEither๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ.

 

4. SwifUI Container๋ฅผ ์ปค์Šคํ…€์œผ๋กœ ๋งŒ๋“ค ๋•Œ 

- SwiftUI์˜ VStack, HStack ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ.

struct CustomStack<Content: View>: View {
    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        VStack(alignment: .leading) {
            content()
        }
    }
}

๐Ÿ‘‰ ์ด๋Ÿฌ๋ฉด CustomStack { ... } ํ˜•ํƒœ๋กœ ๋‚ด๊ฐ€ ๋งŒ๋“  Stack์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.

 

 

 

โœ… ์–ธ์ œ ์•ˆ ์จ๋„ ๋˜๋Š”๊ฐ€?

  • ์ผ๋ฐ˜์ ์ธ View ํŒŒ์ผ์—์„œ body๋ฅผ ์ž‘์„ฑํ•  ๋•Œ (์ž๋™ ์ ์šฉ๋จ)
  • ๋‹จ์ผ View๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜

 

๊ทธ๋Ÿผ ViewBuilder๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผํ•  ์ ์ด ์žˆ์„๊นŒ ?

โœ… ViewBuilder ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

1. ๋ฐ˜ํ™˜ View๋Š” ํ•ญ์ƒ ๋™์ผํ•œ ํƒ€์ž…์œผ๋กœ ๋ฌถ์—ฌ์•ผ ํ•œ๋‹ค

- ViewBuilder๋Š” ์—ฌ๋Ÿฌ View๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ, Swift ๋Š” ๊ฒฐ๊ตญ body์—์„œ ํ•˜๋‚˜์˜ View ํƒ€์ž…๋งŒ ํ•„์š”ํ•จ.

โœ”๏ธ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋ƒ๋ฉด → SwiftUI๊ฐ€ ๋‚ด๋ถ€์—์„œ TupleView๋‚˜ Group์œผ๋กœ ๋ฌถ์–ด์คŒ.

VStack {
    if condition {
        Text("True")
    } else {
        Image(systemName: "star") // ๊ฐ€๋Šฅ, but ์ฃผ์˜ ํ•„์š”
    }
}

โœ”๏ธ ์ฃผ์˜:
SwiftUI๊ฐ€ ์•Œ์•„์„œ ๋ฌถ์–ด์ฃผ๊ธด ํ•˜์ง€๋งŒ, ๋ณต์žกํ•œ ๊ฒฝ์šฐ Swift๊ฐ€ ํƒ€์ž… ์ถ”๋ก ์„ ๋ชป ํ•  ์ˆ˜๋„ ์žˆ์–ด.

๐Ÿ‘‰ ์ด๋Ÿด ๋• Group {}๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋ฌถ์–ด์ฃผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์–ด.

 

๐Ÿ”ฅ Group์€ ๋ญ๋ƒ๋ฉด:

Group์€ SwiftUI๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํƒ€์ž… ์ค‘๋ฆฝ ์ปจํ…Œ์ด๋„ˆ์•ผ.
๋‚ด๋ถ€์— ์–ด๋–ค View๊ฐ€ ๋“ค์–ด์˜ค๋“  ํ•ญ์ƒ ๊ฐ™์€ ํƒ€์ž…: Group<_Content>

VStack {
    if condition {
        Group { Text("True") }
    } else {
        Group { Image(systemName: "star") }
    }
}

๐Ÿ‘‰ ํƒ€์ž… ๊ด€์ ์—์„œ ๋ณด๋ฉด:

  • Group { Text("True") } → ํƒ€์ž…: Group<Text>
  • Group { Image(systemName: "star") } → ํƒ€์ž…: Group<Image>

 

 

2. ๋ณต์žกํ•œ ์กฐ๊ฑด๋ฌธ ์ค‘์ฒฉ ์‹œ ํƒ€์ž… ์ถ”๋ก ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ

- if, else if, else ๊ฐ™์€ ๋ณต์žกํ•œ ๋ถ„๊ธฐ๋ฌธ์ด ๋งŽ์•„์ง€๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž…์„ ์ œ๋Œ€๋กœ ์ถ”๋ก  ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ

โœ”๏ธ ์ด๋Ÿด ๋•Œ๋„ Group์„ ์ž˜ ์จ์ฃผ๊ฑฐ๋‚˜, View๋ฅผ ๋”ฐ๋กœ ๋นผ์ฃผ๋Š” ๊ฒŒ ์ข‹์•„.

 

3. ViewBuilder๋Š” View์—์„œ๋งŒ ์“ธ ์ˆ˜ ์žˆ์Œ

- ViewBuilder๋Š” SwiftUI View ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์œ ํšจ.

๋กœ์ง ์ฝ”๋“œ, ์ผ๋ฐ˜ํ•จ์ˆ˜์—์„œ๋Š” ์‚ฌ์šฉ ๋ถˆ๊ฐ€, ํ•ญ์ƒ View๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•จ

 

4. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธธ ๋•Œ escaping ์ฃผ์˜ 

let content: () -> Content

- ๋ณดํ†ต ์ด๋ ‡๊ฒŒ ์„ ์–ธํ•˜์ง€๋งŒ, ViewBuilder๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ -> @escaping์„ ๋ถ™์ด๋Š” ๊ฑธ ์žŠ์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

โœ”๏ธ SwiftUI์˜ ๋Œ€๋ถ€๋ถ„์˜ API๋Š” ์ด ๋ถ€๋ถ„์„ ์ด๋ฏธ ์ฒ˜๋ฆฌํ•ด์ฃผ์ง€๋งŒ, ๋‚ด๊ฐ€ ์ง์ ‘ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋• ๊ผญ ํ™•์ธํ•ด์•ผ ํ•ด.

 

 

5. ViewBuilder ๋‚ด๋ถ€๋Š” ์ตœ๋Œ€ 10๊ฐœ๊นŒ์ง€๋งŒ View๋ฅผ ์ง์ ‘ ๋‚˜์—ด ๊ฐ€๋Šฅ (Swift ์ œํ•œ)

์ด๊ฑด Swift ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ œ์•ฝ์ธ๋ฐ:

VStack {
    Text("1")
    Text("2")
    ...
    Text("11") // ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ์—๋Ÿฌ๋‚  ์ˆ˜๋„ ์žˆ์Œ
}

โœ”๏ธ Swift์˜ Tuple์ด 10๊ฐœ๊นŒ์ง€๋งŒ ์ง€์›๋ผ์„œ, 11๊ฐœ ์ด์ƒ View๋ฅผ ๋‚˜์—ดํ•˜๋ฉด Swift๊ฐ€ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ•ด.

 

๐Ÿ‘‰ ์ด๋Ÿด ๋• ForEach๋กœ ๋ฐ”๊ฟ”์„œ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ:

VStack {
    ForEach(0..<11) { index in
        Text("\(index)")
    }
}

 

 

6. ViewBuilder๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฆฌํ„ด๊ฐ’ ํ•จ์ˆ˜์™€ ๋‹ค๋ฅด๋‹ค

- ํ•จ์ˆ˜์—์„œ ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋‚˜์—ดํ•ด๋„ return์„ ์“ฐ์ง€ ์•Š๊ณ  ๋งˆ์ง€๋ง‰ ์ค„์„ ๋ฆฌํ„ดํ•˜๊ฒŒ ์ž‘์„ฑํ•ด์•ผ๋จ !! 

- SwiftUI์˜ ์„ ์–ธ์  ๋ฌธ๋ฒ• ์Šคํƒ€์ผ 

 

โœ”๏ธ ๋งŒ์•ฝ return์„ ์“ด๋‹ค๋ฉด → ์ปดํŒŒ์ผ ์˜ค๋ฅ˜ ๋‚  ์ˆ˜๋„ ์žˆ์–ด. !!

 

 

 

๋ฐ˜์‘ํ˜•