SwiftUI using Swift enum for state in UI.
This exists to demonstrate a way of changing state within a View
in a data-driven way.
The key points in using enum
combined with switch
are the following:
- simplified
View
(in this caseContentView
) - no checks i.e
if let
> more readable - data-driven UI, not imperative
The last point is very important and will be further demonstrated in the next section where comparisons are made. While SwiftUI itself is declarative, it is easy to create a system where one has to be cautious about which state the app is in. This creates overhead, confusion and easy mistakes.
The app could easily have been written in the following way for ContentView
:
VStack {
if let isSuccess { LoggedInView() }
if let isFailure { FailedLoginView() }
if let isLogin { LoginView() }
}
However, several issues exists here:
- the app should not be able to show more than one View simultaneously
- added overhead because we have to manually change one or more of
isSuccess
,isFailure
andisLogin
This is compared to the current setup:
switch viewModel.currentState {
case .fail:
FailedLoginView(previousScreen: $viewModel.didGoBack)
case .success:
LoggedInView(previousScreen: $viewModel.didGoBack)
case .login:
LoginView(isLoggedIn: $viewModel.didLogin)
}
Where we only need to care about changing one setting, to define what the state should be in.
In the enum
setup there are only 3 states ContentView
can be in, while without the usage of enum
it jumps up to 2^3 which is 8!
The viewModel
(or whatever one is using) will in this case be a bit more messy due to didSet
on variables. It is also important (as always) to have good names (which I lack in this example).
A potential benefit is using associated values in the enum cases to send info to a specific View.
case success(username: String) // ViewModel enum
case .success(let username): // ContentView
LoggedInView(username: username)
...
That would implicitly mean that when a didSet { }
occur for var didLogin
some value was retrieved and passed to the .success
case.