I'm trying to refactor some code I have and thought I'd be able to move some of the code from globally accessible enum into the ViewModel of the app.
However, when I try to access it from the View it doesn't seem to be accessible or even an option in the autocomplete.
I was wondering if there was a reason why this was the case and if there was something I was missing..
// view
struct MyView: View {
@StateObject var vm = MyViewModel()
var body: some View {
ForEach(vm.MyEnum.allCases, id: \.self) { item in
...
}
}
}
// view model
final class MyViewModel: ObservableObject {
enum MyEnum: String, CaseIterable {
case a, b, c
}
}
I seem to be able to access everything else in a View Model but when it comes to enums they are not. I tried reading about enums to see why, but most things I come across are mainly "how-to" but nothing deep diving why.
CodePudding user response:
Your problem isn't really about enum
s, it's more about properties vs types. When you do this:
final class MyViewModel: ObservableObject {
enum MyEnum: String, CaseIterable {
case a, b, c
}
}
... you're defining 2 types.
MyViewModel
, which is aclass
MyEnum
, which is anenum
It doesn't matter that your MyEnum
is nested inside MyViewModel
— it's still just a type, not a property.
Properties are declared with let
or var
. For example:
final class MyViewModel: ObservableObject {
let myEnumArray = [MyEnum.a, MyEnum.b, MyEnum.c] /// create an instance property
enum MyEnum: String, CaseIterable {
case a, b, c
}
}
struct MyView: View {
@StateObject var vm = MyViewModel()
var body: some View {
/// access the instance property here!
ForEach(vm.myEnumArray, id: \.self) { item in
/// ...
}
}
}
In the above code I've created a new property, myEnumArray
, which you can access with vm.myEnumArray
. This will work.
Now what if you want to access MyEnum
's allCases
? Note that this property is static — the property belongs to the type itself and not an instance of the type. That's why it's not showing up in your autocomplete. Example:
MyViewModel.MyEnum.allCases /// Works! The type is `MyViewModel.MyEnum` and I'm accessing the static `allCases` property.
@StateObject var vm = MyViewModel()
vm.MyEnum.allCases /// NO! the `MyEnum` property doesn't exist inside `vm`.
So your code really has 2 problems.
- You think
MyEnum
is a property. No, it's a type! - Because
MyEnum
is a type, you can't access it withvm.MyEnum
(that's how you access an instance property). You need to doMyViewModel.MyEnum
.
Here's the fixed code:
struct MyView: View {
var body: some View {
ForEach(MyViewModel.MyEnum.allCases, id: \.self) { item in
/// ...
}
}
}