我在视图中创建了一个对象,如何将此对象作为 ObservedObject 传递给子视图?

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

我正在尝试创建 Recpipe 对象(CoreData 实体),然后在创建该对象后将其传递给 ChildView。执行此操作的最佳方法是什么?

我的第一次尝试是在 MainView 中创建一个 @StateObject,然后将其作为 @ObservedObject 传递给 ChildView,但这似乎只适用于已经存在的对象。 @StateObject 是一个 'get only' 属性 所以我不能根据函数 return 修改它。也许我真的不想在这种情况下创建一个@StateObject?

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)
    }
}

通常你将对象保存在 @State 中,或者更好的是在结构中保存所有 ChildView 的相关变量,这样它就可以独立测试,例如

struct ChildViewConfig {
    var recipe: Recipe?
    var isPresented = false
    
    mutating func present(viewContext: NSManagedObjectContext) {
        recipe = Recipe(context: viewContext)
        isPresented = true
    }

    // might have other save or dismiss mutating funcs here.
}

struct MainView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @State private var config = ChildViewConfig()
    
    var body: some View {
        VStack {
            Button("Present") {
                config.present(context: viewContext)
            }
        }
        .sheet(isPresented: $config.isPresented, onDismiss: nil) {
            ChildView(recipe: config.recipe!)
        }
    }
}

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

使用您可能更喜欢的更高级的 .sheet(item:onDismiss),因为它专为编辑项目的这种用例而设计,并允许使用子上下文便签本,因为在设置项目时为 nil 表示如果 sheet 中的编辑被取消,item.childContext 将被丢弃。

4:18 in Data Essentials in SwiftUI (WWDC 2020)

了解有关此 @State Config 结构模式的更多信息

您可以取而代之的是一些应用状态或管理器的概念(任何代表业务逻辑的东西),这将 hold/update 您的食谱,例如

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
            })
        }
    }
}