So I tried to use multiple trailing closures for the first time today, and the inability to specify a label for the first closure really hurts.
Consider SwiftUI's GroupBox
. This is how it generally looks when using a simple text label:
GroupBox(label: Text("Some Group")) {
TextField(...)
.blah()
.blah()
.blah()
}
This works well, in particular because it mirrors how group boxes actually look - with their labels on top:
It's also nice for people reading the code - it serves sort of like a divider, like a // MARK: - Some Group
comment, telling people as they read the code (from top to bottom), that we're entering the portion which defines the content of "Some Group".
Now, I wanted to use a somewhat flashier GroupBox label, with a button to the side. My first thought was to write something like this, replacing the in-line Text
with a @ViewBuilder
:
GroupBox {
HStack {
Text("Some Group")
Spacer()
FlashyControl()
}
} content: {
TextField(...)
.blah()
.blah()
.blah()
}
The added complexity does make it a little less clear and dilutes some of the benefits that we used to have, but it's not too bad as long as the label remains relatively noncomplex.
But what I've found is that, when the label is provided by a @ViewBuilder
, the SwiftUI team have reversed the order of the arguments, so the content comes first, and the label comes afterwards. It feels backwards, and it is backwards compared to GroupBox
's other initializers. So now what I need to write is this:
GroupBox {
TextField(...)
.blah()
.blah()
.blah()
} label: {
HStack {
Text("Some Group")
Spacer()
FlashyControl()
}
}
I can only speculate as to why they've made this decision (if they're reading this, please confirm/deny), but my guess would be that, in a language where the first closure cannot be labelled, in some way it becomes more intuitive for that closure to contain the body of the GroupBox
. That's sort of the "main thing", and since you don't have the label to make it clear which is which, it's sort of clearer? Kind of? Ish?
But in any case, I think the result is fairly poor. It doesn't read well, and actually feels wrong. The thing I would really love to see is this:
GroupBox label: {
HStack {
Text("Some Group")
Spacer()
FlashyControl()
}
} content: {
TextField(...)
.blah()
.blah()
.blah()
}
Alternatively, I think something like this, with an analogous structure to a switch
statement, would look even nicer and clearer:
GroupBox {
label:
HStack {
Text("Some Group")
Spacer()
FlashyControl()
}
content:
TextField(...)
.blah()
.blah()
.blah()
}
But yeah, not even having the option to specify a leading label isn't very nice. It looks so wrong that I'm not even going to use the @ViewBuilder
overload provided by SwiftUI - I'm just going to write my own helper which uses the label-first order, and enclose it in parenthesis rather than use trailing closures.