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.
>Solution :
Your problem isn’t really about enums, 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 aclassMyEnum, 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 a property!
enum MyEnum: String, CaseIterable {
case a, b, c
}
}
struct MyView: View {
@StateObject var vm = MyViewModel()
var body: some View {
/// access it 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
MyEnumis a property. No, it’s a type! - Because
MyEnumis 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
/// ...
}
}
}