在Swift中有几种引用,一个通过@Binding var Param来引用原变量的值,在子函数或子View中修改 Param,但我们也经常使用@EnvironmentObject来引用全局数据。
例如:
struct TestEnvSubView: View {
@EnvironmentObject var globalData : GlobalData
@Binding var firstID:Int
@Binding var secondID:Int
@State private var showEditDetail = false
var body: some View {
@State var myData = globalData[firstID][secondID]
VStack {
Button(action: {
myData.Name = "test"
self.showEditDetail = true
})
{
Text(myData.Name)
}
}
}
}
在这个例子中,我们通过定义
@EnvironmentObject var greenhouseData : GreenhouseData
来引用全局的数据GreenhouseData,当然在上一层View中,应该有加载 .environmentObject(greenhouseData),不然在子View也加载不到数据。
如
struct testPlant: Identifiable {
let id = UUID()
var Name: String
}
class GlobalData: ObservableObject {
@Published var globalData: [[Greenhouse]] = [[]]
init() {
let globalData1 = [testPlant(Name: "Plant 1"), testPlant(Name: "Plant 2")]
let globalData2 = [testPlant(Name: "Plant 3"), testPlant(Name: "Plant 4")]
globalData = [globalData1, globalData2]
}
}
struct TestEnvParentView: View {
@StateObject var globalData = GlobalData()
@State private var firstID = 0
@State private var secondID = 0
@State private var showDetail = false
@Environment(\.presentationMode) var presentationMode
var body: some View {
VStack() {
Spacer()
Button(action: {
self.showDetail = true
})
{Text("click")}
}
Spacer()
}
}
}.sheet(isPresented: $showDetail){
TestEnvSubView(firstID:$firstID,secondID:$secondID)
}
.environmentObject(globalData)
}
}
但发现点击Button后,Text(myData.Name)没有变化,我在想不是@EnvironmentObject来引用全局数据,怎么就没更改呢。
其实是因为:@State var myData = globalData[firstID][secondID]是一个复制变量,并不是原globalData[firstID][secondId]的副本的引用,而修改myData,是不会对myData影响的。
第一步:我想是不是,可以直接操作globalData[firstID][secondID],
修改下代码为:
var body: some View {
@State var myData = globalData.[firstID][secondID]
VStack {
Button(action: {
self.globalData.[firstID][secondID].Name = "test"
self.showEditDetail = true
})
{
Text(myData.Name)
}
}
}
点击Button后,Text(myData.Name)变化了,并且返回上一层View也变化了。
这直接操作globalData[firstID][secondID]是成功的!!!
但是我感觉这么直接操作globalData[firstID][secondID],太繁琐了,能不能用一个变量赋值,就简单点。
第二步:我就想用@State var myData = globalData.[firstID][secondID]修改为
var myData = globalData[firstID][secondID],但运行后,@State var myData = globalData.[firstID][secondID].Name没有变化!这是什么鬼。
分析:
var myData = globalData[firstID][secondID], 应该是 globalData[firstID][secondID]的一个复制品,
第三步:使用var myData = $globalData[firstID][secondID]来引用原数据,再直接wrappedValue访问,并修改它的值。
var body: some View {
var myData = $globalData.[firstID][secondID]
VStack {
Button(action: {
myData.wrappedValue.Name = "test"
self.showEditDetail = true
})
{
Text(myData.wrappedValue.Name)
}
}
}
发现是成功的!
总结:为什么不同的方法访问globalData[firstID][secondID],修改都不行呢, 这里总结下:
1、@State myData = globalData[firstID][secondID]
这个方式使用了@State
属性包装了myData变量,以便你可以在视图中使用它,并在需要时更新它。当你使用这种方式时,myData变量的值会在视图重绘时被重新初始化。因此,如果你想要在视图之间共享数据,你应该使用其他方法。
当你将数据源中的globalData数组中的某个元素存储在@State
属性中时,它会创建一个myData变量的本地副本,而不是引用原始数据源中的testPlant实例。因此,对myData变量的任何更改都不会影响原始数据源中的testPlant实例。
2、let myData = globalData[firstID][secondID].wrappedValue
这个方式使用了wrappedValue
属性来获取绑定属性的实际值,并将其存储在myPlant
变量中。当你使用这种方式时,myData变量存储的是数据源中的testPlant实例的一个副本,而不是一个绑定属性的引用。因此,如果你修改myData变量的值,它不会更新到数据源中。
3、let myData = $globalData[firstID][secondID]
----唯一可以在视图中直接修改globalData[firstID][secondID].原值的方法。
这个方式使用了$
符号来获取绑定属性的引用,以便你可以在视图中修改数据源中的属性或变量。当你使用这种方式时,myData变量存储的是一个绑定属性的引用,你可以使用它来更新数据源中的属性或变量。但是,当你访问myData变量的值时,它返回的是绑定属性的实际值,而不是绑定属性的引用,需要使用 myData.wrappedValue.Value来修改原值:
myData.wrappedValue.Name = "test"
4、let myData = $globalData[firstID][secondID].wrappedValue
这个方式结合了前两种方式的特点,使用了$
符号来获取绑定属性的引用,并使用wrappedValue
属性来获取绑定属性的实际值。当你使用这种方式时,myData变量存储的是数据源中的testPlant实例的一个副本,而不是一个绑定属性的引用。
最后:还有一个问题:
使用let myData = $globalData[firstID][secondID]时,为什么一定用myData. wrappedValue.Name = newValue 修改,而不是myData.Name = newValue来修改?
原因是:文章来源:https://www.toymoban.com/news/detail-462700.html
使用 myData.wrappedValue.Name = newValue
来修改 globalData 对象的属性,而不是使用 myData.Name = newValue
。这是因为 myData 变量实际上是一个 Binding
对象,而 Name
属性是 testPlant
对象的一个属性。如果你直接使用 myData.Name = newValue
来修改属性,编译器会报错,因为 Binding
对象没有 Name
属性。文章来源地址https://www.toymoban.com/news/detail-462700.html
到了这里,关于SwiftUI中EnvironmentObject使用中,直接修改数据源的原值的方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!