4
votes

If I want to render a list of item in SwiftUI, I could do something like this (using XCode 12):

struct MyView: View {
    let texts: [String]
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(texts.indices, id: \.self) { index in
                    MyRow(label: texts[index])
                }
            }
        }
    }

    struct MyRow: View {
        let label: String
        var body: some View {
            Text(label).font(.title3).padding()
        }
    }
}

Instead of being a struct, MyRow can be a function, which makes the code a bit more concise and functional:

struct MyView: View {
    let texts: [String]
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(texts.indices, id: \.self) { index in
                    MyRow(label: texts[index])
                }
            }
        }
    }

    @ViewBuilder func MyRow(label: String) -> some View {
        Text(label).font(.title3).padding()
    }
}

I'd like to understand the difference between the two approaches. Are there cases where you would prefer one over the other?

The first thing that comes to mind is that you cannot have @State properties with functions, which means that you need to use the struct approach if your view needs state.

Is that all? Are there cases where one approach is better in terms of optimisation? Debugging? Features? Portability?

1
Separated view has own refreshing cycle (depending on own states), but view returned from function will always be rebuilt/refreshed in caller body. - Asperi
A result of that is that the ViewBuilder approach seems to be great, until you need a preview with mutable state. - Jessy

1 Answers

0
votes

@ViewBuilder is mostly used to conditionally render views without using parsers like AnyView(YourView). To quote Apple Developer's website: "Clients of this function can use multiple-statement closures to provide several child views". For example, if you want to show a view depending on a variable, i.e. rendering View1 if a certain variable is true and View2 if it is false.