如何更新不同结构中的变量 Swift
How to update variable proper in different struct Swift
在下面的代码中,变量 "yourVariable" 是在结构中定义的。然后我使用滑块更改 "yourVariable" 但是当我尝试在 SecondView 中使用变量时,它使用原始变量而不是更新后的变量。我被告知我需要更新 属性,我应该这样做吗?如果是,有人可以解释原因吗。
import SwiftUI
import PlaygroundSupport
struct MyVariables {
static var yourVariable = 500000.0
}
struct SecondView : View {
@Environment(\.presentationMode) var presentationMode
var string = MyVariables.yourVariable
var body: some View {
VStack {Button("\(string)") {
self.presentationMode.wrappedValue.dismiss()
}
}
}
}
struct ContentView : View {
@State private var showingSheet = false
@State public var step = 0
@State public var text = ""
@State public var slide = 20.0
@State public var slidetwo = MyVariables.yourVariable + 60000
var r0 : Double {
rvalues[(wearingMaskToggle ? 1:0) + (washingHandsToggle ? 2:0) + (quarantineToggle ? 8:0) + (coverMouthToggle ? 4:0)]
}
@State private var rvalues = [6.5, 6.1, 5.3, 4.8, 4.2, 3.5, 3.1, 2.9, 1.75, 1.5, 1.2, 1.0, 0.92, 0.82, 0.75, 0.7]
var body: some View {
ZStack {
Color.gray
.edgesIgnoringSafeArea(.all)
VStack {
HStack {
Button(action: {
if self.slidetwo > 10000{
self.slidetwo -= 1000 //When rand = 10050, it still works
}
}, label: {
Image(systemName: "minus")
})
Slider(value: $slidetwo, in: 10000...1000000, step: 1000)
.padding(20)
.accentColor(Color.green)
Button(action: {
if self.slidetwo < 1000000{
self.slidetwo += 1000
}
}, label: {
Image(systemName: "plus")
})
}.foregroundColor(Color.green) .padding(.horizontal, 100)
}
Text("Initial Population: \(Int(slidetwo))")
Button("Show Sheet") {
self.showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
SecondView()
}
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
首先,滑块正在更新变量 slidetwo
的初始值为 560000
。
当您打开第二个视图时,您正在将结构的值放入变量 string
将导致始终具有 yourVariable
定义的值,因此移动滑块根本不影响第二个视图。
为了正确执行此操作,您可以使用 Binding
以防您希望在第二个视图中更改变量并将这些更改反映在 ContentView
或简单的 un-已初始化 @State var
使用第二个选项会导致在 SecondView
var string = MyVariables.yourVariable
中用 @State var string: String
替换
然后在 sheet 里面的 ContentView
你调用 SecondView(string: String(slidetwo))
而不是 SecondView()
我不明白为什么你需要一个结构在这里。它所做的只是保留一个默认值,仅此而已,您不会在任何地方更新变量。无法绑定,无法直接更新
更新 1:
根据您的评论,我的理解是您希望 SecondView 有多个变量,如果是这种情况,您最好将 ObservableObject
与 EnvironmentObject
[=34= 结合使用]
而且这很容易做到。首先创建一个 class 来保存所有变量。此 class 继承自 ObservableObject
class MyVariables: ObservableObject {
@Published var sliderTwo: Double = 0.0
@Published var yourVariable = 500000.0 // <- I don't know the purpose of this
init() {
sliderTwo = yourVariable + 60000 // <- This is the original value, in the original code
}
}
现在,在第一个视图中,您要初始化 class 并在需要的地方使用它。此时第二张幻灯片不会更新 @State
变量,而是更新模型中的变量,我们需要像这样将 ObservedObject
传递给第二个视图。
struct ContentView: View {
@ObservedObject var model: MyVariables = MyVariables()
//@State public var slidetwo = MyVariables.yourVariable + 60000 <- no longer needed
// ... change every other reference of slidertwo to model.slidertwo
// except the following one witch instead of $slidertwo it will be $model.slidertwo
Slider(value: $model.slidertwo, in: 10000...1000000, step: 1000)
// ...
.sheet(isPresented: $showingSheet) {
SecondView().environmentObject(self.model) // send the model as an environment object
}
}
现在我们将在第一个视图上更新了数据的模型发送到第二个视图,任何更改都会反映在两个视图中,最后一件事,在第二个视图中捕获此 EnvironmentObject
查看
struct SecondView: View {
// var string = MyVariables.yourVariable <- no longer needed
@EnvironmentObject var model: MyVariables
// ....
}
在这种情况下,model.yourVariable
仍然没有改变,因为我们正在更新 model.slidertwo
变量。
对模型所做的更改将反映在两个视图中。
根据我的经验,这是在 SwiftUI 中做事的正确方法
恐怕我来不及了,但您还可以在代码中进行调整,将 slideTwo 变量更改为。
@Binding public var slidetwo: Double
您必须直接在结构中执行 +60000 加法,然后按如下方式初始化您的视图:
PlaygroundPage.current.setLiveView(ContentView(slidetwo: .init(get: { () -> Double in
return MyVariables.yourVariable
}, set: { (newValue) in
MyVariables.yourVariable = newValue
})))
这将导致将对 slideTwo
的所有更改也应用到 yourVariable
。但是,正如 Pedro 已经提到的,我不建议使用结构的这种方法。
在下面的代码中,变量 "yourVariable" 是在结构中定义的。然后我使用滑块更改 "yourVariable" 但是当我尝试在 SecondView 中使用变量时,它使用原始变量而不是更新后的变量。我被告知我需要更新 属性,我应该这样做吗?如果是,有人可以解释原因吗。
import SwiftUI
import PlaygroundSupport
struct MyVariables {
static var yourVariable = 500000.0
}
struct SecondView : View {
@Environment(\.presentationMode) var presentationMode
var string = MyVariables.yourVariable
var body: some View {
VStack {Button("\(string)") {
self.presentationMode.wrappedValue.dismiss()
}
}
}
}
struct ContentView : View {
@State private var showingSheet = false
@State public var step = 0
@State public var text = ""
@State public var slide = 20.0
@State public var slidetwo = MyVariables.yourVariable + 60000
var r0 : Double {
rvalues[(wearingMaskToggle ? 1:0) + (washingHandsToggle ? 2:0) + (quarantineToggle ? 8:0) + (coverMouthToggle ? 4:0)]
}
@State private var rvalues = [6.5, 6.1, 5.3, 4.8, 4.2, 3.5, 3.1, 2.9, 1.75, 1.5, 1.2, 1.0, 0.92, 0.82, 0.75, 0.7]
var body: some View {
ZStack {
Color.gray
.edgesIgnoringSafeArea(.all)
VStack {
HStack {
Button(action: {
if self.slidetwo > 10000{
self.slidetwo -= 1000 //When rand = 10050, it still works
}
}, label: {
Image(systemName: "minus")
})
Slider(value: $slidetwo, in: 10000...1000000, step: 1000)
.padding(20)
.accentColor(Color.green)
Button(action: {
if self.slidetwo < 1000000{
self.slidetwo += 1000
}
}, label: {
Image(systemName: "plus")
})
}.foregroundColor(Color.green) .padding(.horizontal, 100)
}
Text("Initial Population: \(Int(slidetwo))")
Button("Show Sheet") {
self.showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
SecondView()
}
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
首先,滑块正在更新变量 slidetwo
的初始值为 560000
。
当您打开第二个视图时,您正在将结构的值放入变量 string
将导致始终具有 yourVariable
定义的值,因此移动滑块根本不影响第二个视图。
为了正确执行此操作,您可以使用 Binding
以防您希望在第二个视图中更改变量并将这些更改反映在 ContentView
或简单的 un-已初始化 @State var
使用第二个选项会导致在 SecondView
var string = MyVariables.yourVariable
中用 @State var string: String
然后在 sheet 里面的 ContentView
你调用 SecondView(string: String(slidetwo))
而不是 SecondView()
我不明白为什么你需要一个结构在这里。它所做的只是保留一个默认值,仅此而已,您不会在任何地方更新变量。无法绑定,无法直接更新
更新 1:
根据您的评论,我的理解是您希望 SecondView 有多个变量,如果是这种情况,您最好将 ObservableObject
与 EnvironmentObject
[=34= 结合使用]
而且这很容易做到。首先创建一个 class 来保存所有变量。此 class 继承自 ObservableObject
class MyVariables: ObservableObject {
@Published var sliderTwo: Double = 0.0
@Published var yourVariable = 500000.0 // <- I don't know the purpose of this
init() {
sliderTwo = yourVariable + 60000 // <- This is the original value, in the original code
}
}
现在,在第一个视图中,您要初始化 class 并在需要的地方使用它。此时第二张幻灯片不会更新 @State
变量,而是更新模型中的变量,我们需要像这样将 ObservedObject
传递给第二个视图。
struct ContentView: View {
@ObservedObject var model: MyVariables = MyVariables()
//@State public var slidetwo = MyVariables.yourVariable + 60000 <- no longer needed
// ... change every other reference of slidertwo to model.slidertwo
// except the following one witch instead of $slidertwo it will be $model.slidertwo
Slider(value: $model.slidertwo, in: 10000...1000000, step: 1000)
// ...
.sheet(isPresented: $showingSheet) {
SecondView().environmentObject(self.model) // send the model as an environment object
}
}
现在我们将在第一个视图上更新了数据的模型发送到第二个视图,任何更改都会反映在两个视图中,最后一件事,在第二个视图中捕获此 EnvironmentObject
查看
struct SecondView: View {
// var string = MyVariables.yourVariable <- no longer needed
@EnvironmentObject var model: MyVariables
// ....
}
在这种情况下,model.yourVariable
仍然没有改变,因为我们正在更新 model.slidertwo
变量。
对模型所做的更改将反映在两个视图中。
根据我的经验,这是在 SwiftUI 中做事的正确方法
恐怕我来不及了,但您还可以在代码中进行调整,将 slideTwo 变量更改为。
@Binding public var slidetwo: Double
您必须直接在结构中执行 +60000 加法,然后按如下方式初始化您的视图:
PlaygroundPage.current.setLiveView(ContentView(slidetwo: .init(get: { () -> Double in
return MyVariables.yourVariable
}, set: { (newValue) in
MyVariables.yourVariable = newValue
})))
这将导致将对 slideTwo
的所有更改也应用到 yourVariable
。但是,正如 Pedro 已经提到的,我不建议使用结构的这种方法。