Although it's undeniable that SwiftUI has made breakthroughs in redefining how to build an iOS app, it still has difficulties building a real application which can get quite complex. Also, while SwiftUI is still a kid - we have to accept some issues as well as use hacky solutions and hope it gets better in the next releases.
In this short article, we will help you solve the seemingly small issues that cause quite a lot of problems in SwiftUI. In this article, I will guide you to solve the condition statements issue in SwiftUI
1. Why is it a problem in SwiftUI?
Now, let's check the following code:
var body: some View {
if hasUserLoggedIn {
HomeView()
} else {
AuthenticationView()
}
}
Do you find this code familiar? If a user had logged in, he would visit HomeView, otherwise, he has to login or sign-up. It makes sense, right? But what happens when we try to build? The compiler will introduce an error as follows Function declares an opaque return type but has no return statements in its body from which to infer an underlying type
To understand what's going on, we need to learn a little bit about the concept of opaque return types and prefixed with some
keyword.
We will dive deeper into this at another time. In this article, to avoid getting sidetracked, we are going to make a quick explanation but still making sure it's enough for you to understand the rest.
The main point is that any functions or properties returning an opaque result type (represented by some
keyword) must return the same concrete type. In the example, depending on the condition, we returned different views (HomeView or AuthenticationView). That's why the compiler complains.
2. Some ways to fix it
Solution 1: Wrap it in a stack view or group
Since we knew the reason, this solution is quite easy to understand. A stack view will include different views from conditional statements. So, no matter which concrete view was returned, we always have the stack view type. That is enough to make the compiler happy.
var body: some View {
VStack {
if hasUserLoggedIn {
HomeView()
} else {
AuthenticationView()
}
}
}
In some previous beta version, we had a view container which helped us implement this easily and probably more cleanly: _ ConditionalContent<ContentViewIfTrue,ContentViewIfFalse>.
In terms of mechanism of operations, it is simply just embedding different views into the stack internally, nothing much. For example, you can use VStack. However in the official version, it's no longer used anymore. What a pity, hopefully, it will come back soon.
Solution 2: Use @ViewBuilder
In case you do not want to use an extra view such as VStack or Group, you can annotate the body property as @ViewBuilder.
var body: some View {
if hasUserLoggedIn {
HomeView()
} else {
AuthenticationView()
}
}
But please pay attention to this solution, since developers have reported that some animation behaviors stop working, the toggle, for example. So be careful with this.
Solution 3: Wrap in AnyView
The last solution is using AnyView. The name says it all. You can use AnyView in order to wrap any different views. With this solution, we have the same view returned.
var body: some View {
if hasUserLoggedIn {
AnyView(HomeView())
} else {
AnyView(AuthenticationView())
}
}
Although no longer have to be embedded in the Stack or need to define @ViewModifier, having to see AnyView all the time makes us a little uncomfortable. Every way has its downsides.
Conclusion
In the examples above, we have used if / else to explain the examples but you can also apply these to the switch-case.
Obviously this is not the most expected thing but while waiting for Apple developers to improve this framework, the above solutions are ways to help you deal with condition issues in SwiftUI. Thanks for reading this article and hope this will be helpful to you.
At Instamobile, we're building React Native Templates and iOS App Templates to help developers create their mobile apps much faster.
Resources:
Top comments (0)