在 SwiftUI 中使用 @State 属性包装器未更新视图

Posted

技术标签:

【中文标题】在 SwiftUI 中使用 @State 属性包装器未更新视图【英文标题】:View is not updated using @State property wrapper in SwiftUI 【发布时间】:2020-05-04 19:44:00 【问题描述】:

使用@State 包装器不会更新视图。 视图在不使用 @State 包装器的情况下更新,但必须手动进行。

import SwiftUI

struct SwiftUIView: View 
    @ObservedObject var people: People
    var body: some View 
        VStack 
            ForEach(people.peoples) person in
                HStack
                    Text("\(person.age)")
                    if person.ismale 
                        Text("Male")
                     else 
                        Text("Female")
                    
                    Button(action: person.age += 1)
                        Text("Age+1")
                    
                
            
        
    


struct Person: Identifiable
    var id = UUID()
    @State var age: Int
    var ismale = true


class People: ObservableObject 
    @Published var peoples: [Person]
    init() 
        self.peoples = [
            Person(age: 10),
            Person(age: 12, ismale: false)
        ]
    


struct SwiftUIView_Previews: PreviewProvider 
    static var previews: some View 
        SwiftUIView(people: People())
    


由于某种原因,单击按钮时,视图没有变化。

如果我把它改成

Button(action: **self.people.peoples[0].age += 1** )
       Text("Age+1")

...

struct Person: Identifiable
    var id = UUID()
    **var age: Int**
    var ismale = true

它会更新,但按钮不会是动态的。但是,如果我在 ForEach 循环中执行 person.age += 1 而不使用 @State 变量年龄包装器。

错误:“变异运算符的左侧不可变:'person' 是 'let' 常量”

我以为我理解 Struct、Class、@State 的含义……我想不明白……感谢您提供任何解决方案。

【问题讨论】:

【参考方案1】:

struct 通过引用传递,因此您不需要 @State,因为 ObservableObject 已经收到更新。

这是Person 结构

struct Person: Identifiable
    var id = UUID()
    var age: Int
    var ismale = true

还有SwiftUIView。我删除了If 语句,因此代码更简洁。

ForEach(people.peoples.indices, id: \.self) index in
    HStack
        Text("\(self.people.peoples[index].age)")
        Text(self.people.peoples[index].ismale ? "Male" : "Female")
        Button(action: self.people.peoples[index].age += 1 )
            Text("Age+1")
        
    


【讨论】:

感谢您的解决方案。我真的不明白为什么person.age += 1 在 ForEach 循环中不起作用并输出错误:“变异运算符的左侧不可变:'person' 是 'let' 常量”。你能指出我正确的方向吗?谢谢! 它不起作用,因为在ForEach 循环中,person 是一个常量,不能修改。一般来说,闭包值是一个常数。

以上是关于在 SwiftUI 中使用 @State 属性包装器未更新视图的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中用另一个 @State 属性值初始化 @State 属性

深度解析:为何在 SwiftUI 视图的 init 初始化器里无法更改 @State 的值?

深度解析:为何在 SwiftUI 视图的 init 初始化器里无法更改 @State 的值?

SwiftUI之深入解析@StateObject@ObservedObject和@EnvironmentObject的联系和区别

[SwiftUI 知识碎片] 为什么 @State 只能在结构体中工作

如何在 SwiftUI 中使用 EnvironmentObject 初始化 State 属性?