'I create an object in a view, how do I pass this object to child views as an ObservedObject?

I am trying to create a Recpipe object (CoreData entity) and then pass that object to a ChildView after it's created. What's the best way to do this?

My first attempt was to create a @StateObject in the MainView and then pass that to ChildViews as an @ObservedObject, but this seems to only work great for objects that already exist. The @StateObject is a 'get only' property so I can't modify it based on the function return. Perhaps I don't really want to create a @StateObject in this circumstance?

struct MainView: View {
    
    @State private var presentChildView: Bool = false
    @StateObject private var recipe: Recipe = Recipe()

    var body: some View {
        VStack {
            
            NavigationLink(destination: ChildView(recipe: recipe), isActive: $presentChildView) {
                EmptyView()
            }

            Button("Action", action: {
                recipe = functionThatReturnsRecipe()
                presentChildView = true
            })
        }
    }
}

struct ChildView: View {
    @ObservedObject private var recipe: Recipe
    
    var body: some View {
        Text(recipe.title)
    }
}


Solution 1:[1]

You can have instead some concept of app state or manager (anything represented business logic) which would hold/update your recipes, like

class AppState: ObservableObject {
    @Published var recipe: Recipe = Recipe()

    func refreshRecipe() {
        self.recipe = functionThatReturnsRecipe()    // << now works !!
    }

    private func functionThatReturnsRecipe() -> Recipe {
        Recipe()
    }
}

struct MainView: View {

    @State private var presentChildView: Bool = false
    @StateObject private var appState = AppState()      // << non-changeable

    var body: some View {
        VStack {

            NavigationLink(destination: ChildView(recipe: appState.recipe), isActive: $presentChildView) {
                EmptyView()
            }

            Button("Action", action: {
                appState.refreshRecipe()
                presentChildView = true
            })
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Asperi