SwiftUI:独立视图之间的数据共享

SwiftUI:独立视图之间的数据共享,swiftui,data-sharing,code-separation,Swiftui,Data Sharing,Code Separation,在视图之间共享变量的最佳实践是什么? 我的应用只有一个视图。但随着它变得越来越复杂,我想我应该把它分成几个视图。也要分开的方法。 我是这样开始的: struct ContentView: View { @State var str: String = "String" var body: some View { VStack(alignment: .leading) { Text(str) Tex

在视图之间共享变量的最佳实践是什么? 我的应用只有一个视图。但随着它变得越来越复杂,我想我应该把它分成几个视图。也要分开的方法。 我是这样开始的:

struct ContentView: View {
    @State var str: String = "String"
    var body: some View {
        VStack(alignment: .leading) {
            Text(str)
            TextField("Input", text: $str)
            Button("button", action: { doSomething() })
        }.padding()
    }
    func doSomething() {
        str = str + " " + str
    }
}
class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(str: globalvars.str) //don't need a binding here since it doesn't get modified
            EditView(str: $globalvars.str)
            ControlView(str: $globalvars.str)
        }.padding()
    }
}
struct DisplayView: View {
    var str:  String //don't need a binding here since it doesn't get modified
    var body: some View {
        Text(str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: $str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        str = str + " " + str
    }
}
我想去那里:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
    }
}
struct DisplayView: View {
    @Binding var str:  String
    var body: some View {
        Text(self.globalvars.str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: self.$str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
}
func doSomething() {
    @Binding var str:  String
    self.str = self.str + " " + self.str
}

我尝试了@Published、@ObservedObject和@Binding。但你不明白。提前感谢您的指点。

有很多方法可以实现这一点

我的选择可能是将绑定只传递给您需要访问的变量。可能是这样的:

struct ContentView: View {
    @State var str: String = "String"
    var body: some View {
        VStack(alignment: .leading) {
            Text(str)
            TextField("Input", text: $str)
            Button("button", action: { doSomething() })
        }.padding()
    }
    func doSomething() {
        str = str + " " + str
    }
}
class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(str: globalvars.str) //don't need a binding here since it doesn't get modified
            EditView(str: $globalvars.str)
            ControlView(str: $globalvars.str)
        }.padding()
    }
}
struct DisplayView: View {
    var str:  String //don't need a binding here since it doesn't get modified
    var body: some View {
        Text(str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: $str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        str = str + " " + str
    }
}
请注意,现在在
ContentView
中,有一个传递给每个子视图的参数,其中包含对
GlobalVars
str
属性的绑定(使用
$
符号)

另外,
doSomething
被移动到
ControlView


您还可以使用EnvironmentObject来处理此问题。我个人不太喜欢这种方法,因为我更愿意明确地看到参数的去向。它还允许子视图访问整个ObserveObject,这实际上是不必要的。但是,它向你展示了校长:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
        .environmentObject(globalvars)
    }
}
struct DisplayView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}
struct EditView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        TextField("Input", text: $globalvars.str)
    }
}
struct ControlView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        globalvars.str = globalvars.str + " " + globalvars.str
    }
}

请注意,现在,
globalvars
通过使用
.environmentObject
放置在视图层次结构中传递给子级。每个子视图都可以通过声明
@EnvironmentObject var globalvars:globalvars


您还可以创建一种混合模型,将ObserveObject作为参数显式传递给子视图:

struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(globalvars: globalvars)
        }.padding()
        .environmentObject(globalvars)
    }
}

struct DisplayView: View {
    @ObservedObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}

非常感谢。哇,就是这样。还需要消化答案的第二部分。当我想在多个视图中使用该方法时,我该怎么做?(如果我有后续问题,我是否可以开始一个新问题?“方法”是否意味着
doSomething()
?你可以把它放在
GlobalVars
中。后续问题很好,除非它们只是关于可以快速回答的初始问题的细节。谢谢你的提问!对不起,是的,我指的是函数。我测试了所有3种方法。第一种方法非常漂亮!但对于复杂的场景,混合方法可能可以.现在我需要进入我真正的应用程序。我只是对你在这里提供的顶级支持感到惊讶!你的两个答案为我节省了几天甚至几周的工作。非常感谢!