是否可以通过其结构方法更改@State属性的值?



在Xcode的游戏场地上,我运行以下代码:

import SwiftUI
struct Test {
@State var count: Int = 0   //to avoid "mutating" keyword, I use "@State" property wrapper
func countUp() {
self.count += 1
}
}
var test = Test()
test.countUp()     // I want "count" property to be count up. but it did not
print(test.count)  // print 0

Q( 为什么test.count仍然为0??

这可能不是问题的意图,但我将解释为什么有问题的代码不起作用。(我相信这和评论是一样的。(

您在操场上使用的是SwiftUI,而不是View@State符合DynamicProperty

https://developer.apple.com/documentation/swiftui/statehttps://developer.apple.com/documentation/swiftui/dynamicproperty

文件上说:

您应该只从视图主体内部或从其调用的方法访问状态属性。

存储变量的接口,用于更新视图的外部属性。和在重新计算视图主体之前,视图会为这些特性提供值。

有人建议将其与Viewview’s body一起使用。

如上所述,您的代码不使用Viewview’s body

由于@State只能在struct中使用,如果你想做类似的事情,你可以使用class@Published,如下所示(简单地使用Combine,而不是SwiftUI(:

import Combine
class Test {
@Published var count: Int = 0
func countUp() {
self.count += 1
}
}
var test = Test()
test.countUp()
print(test.count) // 1

然而,您的代码没有人订阅更改,所以这只是一个实验性代码。

不允许在顶层使用表达式。

为了测试您的案例,我创建了一个名为Test1View结构,并在其初始化程序中为Test视图创建了对象。检查下面的代码。

import SwiftUI
struct Test1:View {
init() {
let test = Test() // concentrate on this
test.countUp()     
}
var body: some View {
Test() // Ignore for now
}
}

测试视图-:

import SwiftUI

@propertyWrapper struct TestCount:DynamicProperty {
@State private var count = 0
var wrappedValue: Int {
get {
count
}
nonmutating set {
count = newValue
}
}
init(_ count: Int) {
self.count = count
}
}
struct Test: View {
@TestCount var count:Int

init(count:Int) {
_count = TestCount(count)
print(_count)
}

var body: some View {
Button {
countUp()
} label: {
Text("(count)")
}
}
func countUp()  {
count += 1
print(count)
}
}

为了更好地理解,我创建了一个自定义的propertyWrapper,我们将在Test视图中初始化它。

现在,当您在模拟器中运行此代码时,首先调用Test1视图,并在其初始化程序中为Test()视图创建对象。

初始化后的Test视图将为其名为TestCount的属性包装器创建对象,一旦创建,它将打印TestCount实例的描述,并且注意现在打印输出-:

TestCount(_count:SwiftUI.State<Swift.Int>(_value:0,_location:nil((

您可以清楚地看到状态TestCount包装器中的变量count被分配了默认值0,但尚未分配任何SwiftUI.StoredLocation

现在,这一行在Test1视图中的下一个test.countUp()中执行,因为我们从body属性之外调用它,并且Test1也在body属性之外初始化,所以编译器足够聪明,可以检测到这一点,并且它不会为count变量的此更改提供SwiftUI存储位置,因为此更改不需要视图更新,因此,您总是将输出视为0(默认保存值(。

为了证明我的观点,现在对Test1视图进行以下更改。

import SwiftUI
struct Test1:View {
//    init() {
//        let test = Test(count: 0)
//        test.countUp()     // I want "count" property to be count up. but it did not
//    }
var body: some View {
Test(count: 0)
}
}

现在,测试视图中的初始打印语句是相同的-:

TestCount(_count:SwiftUI.State<Swift.Int>(_value:0,_location:nil((

但是,现在您有了一个带有Button的视图,可以随时更改count变量值。

当你点击按钮时,会再次调用countUp((,这次再次检查print语句的输出,SwiftUI的存储位置不再为零。

TestCount(_count:SwiftUI.State<Swift.Int>(_value:0,_location:可选(SwiftUI.StoredLocation<Swift.Int>((。

您可以进一步调试代码以获得更好的理解,我还建议您更详细地阅读PropertyWrappers,以及它们如何在内部工作。

最新更新