Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Accessing an enum in ObservableObject

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..

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

// 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.

  1. MyViewModel, which is a class
  2. MyEnum, which is an enum

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.

  1. You think MyEnum is a property. No, it’s a type!
  2. Because MyEnum is a type, you can’t access it with vm.MyEnum (that’s how you access an instance property). You need to do MyViewModel.MyEnum.

Here’s the fixed code:

struct MyView: View {
    var body: some View {
        ForEach(MyViewModel.MyEnum.allCases, id: \.self) { item in
            /// ...
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading