在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
文件上说:
您应该只从视图主体内部或从其调用的方法访问状态属性。
存储变量的接口,用于更新视图的外部属性。和在重新计算视图主体之前,视图会为这些特性提供值。
有人建议将其与View
和view’s body
一起使用。
如上所述,您的代码不使用View
或view’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
然而,您的代码没有人订阅更改,所以这只是一个实验性代码。
不允许在顶层使用表达式。
为了测试您的案例,我创建了一个名为Test1
的View
结构,并在其初始化程序中为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
,以及它们如何在内部工作。