$ 在 SwiftUI 中如何工作以及为什么我可以将 @StateObject 转换为 @ObservedObject

问题描述

我是一个新手,正在开发一个应用程序,该应用程序基本上有一个包含食物的冰箱类。我正在尝试拥有一个带有食物清单的冰箱。所以我将 foodList 设置为一个已发布的对象,并在程序启动时实例化一个 @StateObject 冰箱。基本上,从我的角度来看,每当 foodList 发生变化时,冰箱对象都会保存它的状态并给我一个新的视图。

此外,我想将此@StateObject 冰箱传递给另一个视图,以便我的另一个视图可以修改冰箱中的 foodList

下面是我的代码

struct ContentView: View {
    @StateObject private var fridge=Fridge();
    private var dbStartWith=0;
    
    @State private var selection = 1;
    @State private var addFood = false;
    
    var body: some View {
        TabView(selection: $selection) {
            NavigationView {
                List(fridge.container!){
                    food in NavigationLink(destination: FoodView()) {
                        Text("HI")
                    }
                }.navigationBarTitle(Text("Fridge Items"),displayMode: .inline)
                .navigationBarItems(trailing:
                                        NavigationLink(destination: AddFoodView(fridgeView: fridge)) {
                                            Image(systemName: "plus.circle").resizable().frame(width: 22,height: 22)
                                        } )
            }
            .tabItem {
                Image(systemName: "house.fill")
                Text("Home")
            }
            .tag(1)
            
            
            Text("random tab")
                .font(.system(size: 30,weight: .bold,design: .rounded))
                .tabItem {
                    Image(systemName: "bookmark.circle.fill")
                    Text("profile")
                }
                .tag(0)
        }
        
    }
}
    

struct FoodView: View{
    var body: some View{
        NavigationView{
            Text("food destination view ");
        }
    }
}

struct AddFoodView: View{
    @Observedobject var fridgeView: Fridge;
    @State private var name = ""
    @State private var count : String = "1"
    @State private var category : String = "肉类";
    @State var showCategory = false
    @State var showCount = false
    

    var body: some View{
        ZStack{
            NavigationView{
                Form{
                    HStack{
                        Text("食品")
                        TextField("请输入材料名",text: $name);
                    }.padding(.bottom,10).padding(.top,10).padding(.leading,10).padding(.trailing,10)
                    HStack{
                        Text("数量")
                        TextField("请选择数量",text:$count,onEditingChanged:{(changed) in
                            self.hideKeyboard();
                            self.showCount=changed;
                        }){}
                    }.padding(.bottom,10)
                    HStack{
                        Text("种类")
                        TextField("请选择种类",text: $category,onEditingChanged:{(changed) in
                            self.hideKeyboard();
                            self.showCategory=changed;
                        }){}
                    }.padding(.bottom,10)
                }
            }.navigationBarItems(trailing: NavigationLink(destination: FoodView()){
                Text("保存").foregroundColor(Color.blue).font(.system(size: 18,design: .default))
            }).simultaneousGesture(TapGesture().onEnded{
                var tempFood=Food(id: fridgeView);//not completed yet
            })
            ZStack{
                    if self.showCount{
                        Rectangle().fill(Color.gray)
                            .opacity(0.5)
                        vstack(){
                            Spacer(minLength: 0);
                            HStack{
                                Spacer()
                                Button(action: {
                                    self.showCount=false;
                                },label: {
                                    Text("Done")
                                }).frame(alignment: .trailing).offset(x:-15,y:15)
                            }
                            Picker(selection: $count,label: EmptyView()) {
                                ForEach(1..<100){ number in
                                    Text("\(number)").tag("\(number)")
                                }
                            }.labelsHidden()
                        }            .frame(minWidth: 300,idealWidth: 300,maxWidth: 300,minHeight: 250,idealHeight: 100,maxHeight: 250,alignment: .top).fixedSize(horizontal: true,vertical: true)
                        .background(RoundedRectangle(cornerRadius: 27).fill(Color.white.opacity(1)))
                        .overlay(RoundedRectangle(cornerRadius: 27).stroke(Color.black,linewidth: 1))
                        .offset(x:10,y:-10)
                        Spacer()
                    }
                    if self.showCategory{
                        let categoryArr = ["肉类","蔬菜类","饮料类","调味品类"]
                        ZStack{
                            Rectangle().fill(Color.gray)
                                .opacity(0.5)
                            vstack(){
                                Spacer(minLength: 0);
                                HStack{
                                    Spacer()
                                    Button(action: {
                                        self.showCategory=false;
                                    },label: {
                                        Text("Done")
                                    }).frame(alignment: .trailing).offset(x:-15,y:15)
                                }
                                Picker(selection: $category,label: EmptyView()) {
                                    ForEach(0..<categoryArr.count){ number in
                                        Text(categoryArr[number]).tag(categoryArr[number])
                                    }
                                }.labelsHidden()
                            }            .frame(minWidth: 300,vertical: true)
                            .background(RoundedRectangle(cornerRadius: 27).fill(Color.white.opacity(1)))
                            .overlay(RoundedRectangle(cornerRadius: 27).stroke(Color.black,linewidth: 1))
                            Spacer()
                        }.offset(x:10,y:20)
                    }
            }
        }.animation(.easeInOut)
    }
        
    
}

基本上我想将 @StateObject private var fridge 传递给 struct AddFoodView: View,以便我的 AddFoodView 可以使用该变量。根据我在网上学到的,我认为我需要像这样 @Observedobjects 注入 NavigationLink(destination: AddFoodView(fridgeView: fridge))。这不会给我带来让我困惑的错误(至少在调试器阶段)。 fridge 不是 Food 变量,fridgeView 不是 @Observedobject Food 变量吗?

如果我做这样的事情AddFoodView(fridgeView: $fridge))。有错误Cannot convert value '$fridge' of type 'Observedobject<Fridge>.Wrapper' to expected type 'Fridge',use wrapped value instead

解决方法

@StateObject@ObservedObject 是事实来源,它们彼此非常相似,几乎可以互换。

要与其他 View 共享这些,您应该使用 AddFoodView 将其传递给 .environmentObject(fridge) 并将 @ObservedObject var fridgeView: Fridge; 中的 AddFoodView 更改为 {{1} }.

"Managing Model Data in Your App" 上查找 Apple 文档。

@EnvironmentObject var fridgeView: Fridge

另一个很好的来源是 Apple SwiftUI 教程,尤其是 "Handling User Input"

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...