I learned from this forum a while ago I can add @ViewBuilder to my view's var body: some View {} and use if/else expression inside. But I'm getting this compile error which I cannot understand:
This is how I want to write my code, but compile error:
struct MyIfElseView: View {
@State private var flag = true
@ViewBuilder
var body: some View { // <-- Compile error here "Cannot convert return expression of type '_ConditionalContent<Text, Text>' to return type 'some View'"
if flag {
Text("aaa")
} else {
Text("bbb")
}
}
}
This, which. is exactly the same semantically, is okay:
struct MyIfElseView: View {
@State private var flag = true
var aaa: some View {
Text("aaa")
}
var bbb: some View {
Text("bbb")
}
@ViewBuilder
var body: some View {
if flag {
aaa
} else {
bbb
}
}
}
And most baffling, sticking my if/else inside a Group is fine:
struct MyIfElseView: View {
@State private var flag = true
var body: some View {
Group {
if flag {
Text("aaa")
} else {
Text("bbb")
}
}
}
}
This seems to be a bug that's recently been fixed. This code compiles using Swift master, and I suspect this works on the 5.2 branch as well because many of the function builder and type checking improvements that @TizianoCoroneo mentioned are in the 5.2 branch.
If you'd like to test it out, you can download a recent Swift 5.2 toolchain from Swift.org - Download Swift
You can’t submit an app built by a development snapshot to the App Store, so they’re really just for Swift contributors (including people who want to see if the bug they reported has been fixed) and people who want to learn about what’s coming in future Swift versions (and possibly write long, detailed articles about it). Most people who write Swift apps for Apple platforms should stick to the XcodeDefault toolchain for all of their real work.
There were many PRs that contributed to the type checking improvements - I don't know which one in particular fixed this bug. However, if you're interested in contributing to type checking in the compiler, I recommend reading our recent blog post about the New Diagnostic Architecture, and our documentation on the type checker. These resources will give you a good overview of how the expression type checker works!
I couldn't figure out how to manually transform the if/else to direct call ViewBuilder.builderEither(). Please show how? Thanks!
Also, is there any way to deal with this temporary workaround for now that we know the next Swift fix? Something like this:
#if (SwiftVersion < 52)
// use workaround
ViewBuilder.buildEither(....)
#else
#message("You can remove the workaround now at __FILE__ __LINE__")
// use proper code
if flag {
Text("aaa")
else {
Text("bbb")
}
#endif
Quick question why do you want to wrap the view if it‘s Text in both cases any way?
Version one:
var text: some View {
if flag {
return Text("A")
} else {
return Text("B")
}
}
Version two:
var conditonalText: some View {
typealias MyView = _ConditionalContent<Text, Text>
if flag {
return ViewBuilder.buildEither(first: Text("A")) as MyView
} else {
return ViewBuilder.buildEither(second: Text("B")) as MyView
}
}
In such case the former would be preferred over the latter as SwiftUI won‘t need to remove and recreate a new view for Text.
It's just a simplified example, my actual code is three different kinds of Gradient's:
var colorSetting: some View {
if setting == .gold {
goldColorLinearGradient
} else if setting == .psych {
psychRadialGradient
} else {
dayNightAngularGradient
}
}
I'm actually facing a bit of a problem: the gradients are also ShapeStyle, what I really need is this:
var colorSetting: some ShapeStyle & View {
... 😳 make a type erase AnyShapeStyleAndView()? <<-- option 1
... or build some ConditionalShapeStyleAndView<xxx, yyy> <<-- option 2
}
I cannot figure out how to implement ShapeStyle, so as now, I don't know how to do either options. Anyway, for now, I use them as View, but later I'll also need to use these thing with .strokeBorder(), which takes a ShapeStyle as parameter.
Anyway, looking at your "Version two" is very educational. It shows me how things can be built by hand...