当前位置: 代码网 > it编程>网页制作>Css > SwiftUI中EnvironmentObject使用中,直接修改数据源的原值的方法

SwiftUI中EnvironmentObject使用中,直接修改数据源的原值的方法

2024年07月28日 Css 我要评论
其实是因为:@State var myData = globalData[firstID][secondID]是一个复制变量,并不是原globalData[firstID][secondId]的副本的引用,而修改myData,是不会对myData影响的。var myData = globalData[firstID][secondID],但运行后,@State var myData = globalData.[firstID][secondID].Name没有变化!当你使用这种方式时,

在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来修改?

原因是:

使用 mydata.wrappedvalue.name = newvalue 来修改 globaldata 对象的属性,而不是使用 mydata.name = newvalue。这是因为 mydata 变量实际上是一个 binding 对象,而 name 属性是 testplant 对象的一个属性。如果你直接使用 mydata.name = newvalue 来修改属性,编译器会报错,因为 binding 对象没有 name 属性

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com