Given a custom content view that accepts a ViewBuilder as it's content, when is the best time to execute the ViewBuilder, in the custom views init or in its body?
struct Custom<Content: View>: View {
init(@ViewBuilder content: @escaping () -> Content) {
// Option 1
self.content = content()
// Option 2
self.content = content
}
var body: some View {
...
// Option 1
content
// Option 2
content()
...
}
}
This has been asked before, and the SO answer referenced this Q&A which provides an answer, but it seems somewhat unofficial. Is there any official documentation on this, or an explanation of the pros and cons of each approach.
It's better to pass a non-escaping function and evaluate early, if you can. So, in your example, option 1 and remove
@escaping. When a closure is passed non-escaping, it can be stored entirely on the stack, which is more efficient than storing it on the heap.If you look at SwiftUI's built-in views, you'll find that many of them take non-escaping
@ViewBuilderarguments, which means those views are executing their arguments immediately.For example, the
contentargument ofVStack.initisn't@escaping. This meansVStackcannot storecontentin an instance variable. Therefore we can deduce thatVStack.initexecutescontentimmediately, and cannot in the future be changed to store it for later execution (because adding@escapingis not backward-compatible).Compare with
ForEach.init, where thecontentargument is@escaping. This meansForEachcan storecontentin an instance variable to call later, and we expect it to do so if, for example,ForEachis used insideLazyVStack.