Celebrating 200 Daily Coding Tips š all tutorials will be free to all this week!
(Even though the 200th Daily Coding Tip isnāt until Wednesday š)
Apple has sent mixed messages about when and why the @ViewBuilder
attribute is necessary.
When SwiftUI was first released, it was impossible to build a view without adding it to your body
property. Apple then added the attribute to the body property inside in the View
protocol, meaning that any conforming type secretly had the functionality without it being added manually.
Now that it was hidden away, it became quite ambiguous exactly what the some
View
type does, and whether it ever needs @ViewBuilder
at all.
@ViewBuilder is an example of a result builder, which I covered in more detail in Daily Coding Tip 073. These attributes require the declaration of functions called buildBlock that take a bunch of parameters and condense them down into a single type. SwiftUI is actually heavily reliant on TupleView, which is an interesting type in itself.
Tuples are groups of values that may or may not have labels.
TupleView
takes an associated generic type, but every tuple is different. Itās like being able to specialize with a bunch of generic types at once, which is usually impossible. What @ViewBuilder
does is take the Button
, Text
and Image
passed into a body
property, which are not a single type, and converts them into a type like TupleView<(Button, Text, Image)>
.
To demonstrate what happens when @ViewBuilder
is not part of a protocol, Iāve created my own version of the View
protocol that does not add the attribute.
Now my ConformingView
needs @ViewBuilder
on its body
property, because this is no longer assumed by the protocol.
Iāve also provided an example of a situation when @ViewBuilder
is not needed. When I compute the oneConcreteType
property, I am actually returning a known type. Although some View
is deliberately vague, this is mainly so that I can change the content of my Group
and Swift will infer the type automatically.
If I explicitly stated the type as Group<TupleView<(Text, Text, Text)>>
, I wouldn't need to use the opaque return type some View
.
What if I then removed one Text
?
I would need to manually change the type to Group<TupleView<(Text, Text)>>
.
This would be pretty time consuming during the construction of a view, so itās obvious why Apple had to create the some
keyword to deal with this situation.
Remember, an opaque return type means a single type needs to be returned, whether that be a Group
or a layout type like VStack
or HStack
.
If you insist on returning multiple views, for instance to populate a VStack
or HStack
elsewhere with content, youāll need to add @ViewBuilder
unless itās inside the body property where @ViewBuilder
is automatically provided.