0
votes

I'm new to SwiftUI and MVVM, and the whole though process around @Published is still not making total sense to me.

In my contentView, I have an observable object that reads from a class that adopts the ObservedObject protocol.

Content View:

struct ContentView: View {

      @ObservedObject var exercises: ExerciseSelector = ExerciseSelector()

Separate Class:

class ExerciseSelector: ObservableObject {

      @Published var activeExercises : [SelectedExercises] = []

On another page in my app (a different tab in a TabView), I have a button that should change the 'activeExercises' array.

struct NewRoutine: View {

let exerciseSelector = ExerciseSelector()

...

//Button Function
func printThings() {

    exerciseSelector.select(random: true)

I've put print statements in there to confirm that it did, in fact, change the array (and it does), but it still doesn't show on the first page. My guess is that I'm messing something up by initializing another instance of ExerciseSelector on the second page, and that it's technically not the same one as the ContentView is observing. So I tried to fix this by creating a singleton within the ExerciseSelector class that both views can read off of.

static let shared = ExerciseSelector()

This works, but I feel like it's not really the "correct" way to do it.

Is there a better way to make this all work, or is the singleton approach the best way to do it?

1
Lol you putting "single source of truth" in quotation marks makes me believe that it is quite the common thing in SwiftUI! But thanks! I'm going to try to figure out how to apply @EnvironmentObject in there, but it's nice to know that I'm not horribly breaking anything! Do you want to add your response as an answer so I can accept it? - Jeff Cournoyer
'static let shared = ExerciseSelector()" is the best way to do it. Otherwise you have to manage the injection of an Environment object. This works well and predictably and perfectly conforms to MVVM. - Yrb
@Yrb A static property is certainly one way to do it, but I'd argue that the @EnvironmentObject strategy is the one that more closely resembles the way SwiftUI is supposed to be used. - West1
My issue with @EnvironmentObjects is the injection. You end up with a two step process to use it, and I have found it be a little flaky at times. I will admit not having used it since 5.3. I agree that in thought @EnvironmentObject is the preferred method, but @ObservableObject ticks all the same boxes. - Yrb

1 Answers

1
votes

If ExerciseSelector and its array is your "single source of truth" then you need to do something like you have already done so that both views can use the same instance. Another option to look into is to use a @EnvironmentObject which is a different way of achieving basically the same. See this article for instance to learn about EnvironmentObject