@State 在可变函数和初始化器中改变后不更新 SwiftUI 视图

7

我尝试了多种方法来更新SwiftUI视图中的@State。有些方法会导致状态更改后更新相关视图,而其他方法则不会。

@State更改会更新视图

@State var bodyText: String = "Hello swift"

var body: some View {
    Text(bodyText)
        .onAppear(perform: triggerTextUpdate)
}

private func triggerTextUpdate() {
    DispatchQueue.main.asyncAfter(deadline: .now()+3) {
        bodyText = "Hello I am future swift"
    }
}

@State变化不更新视图

1. 从初始化器中更改@State

@State var bodyText: String = "Hello swift"
init() {
    triggerTextUpdate()
}

var body: some View {
    Text(bodyText)
}

private func triggerTextUpdate() {
    DispatchQueue.main.asyncAfter(deadline: .now()+3) {
        bodyText = "Hello I am future swift"
    }
}

2. @State从可变函数(mutating function)中更改

@State var bodyText: String = "Hello swift"
private let somePublishSubject = PublishSubject<String, Never>()
private var subscriptions = Set<AnyCancellable>()

init() {
    setUpBinding()
}

var body: some View {
    Text(bodyText)
}

mutating func setUpBinding() {
    somePublishSubject.sink { [self] text in
        self.bodyText = text
    }.store(in: &subscriptions)
}

当调用somePublishSubject并改变bodyText状态时,视图不会更新。
SwiftUI 的文档不是很多,这使得理解为什么视图更新和@State更改变得更加混乱。对于这种行为的任何解释都将非常有帮助。

因为您的函数在视图主体初始化之前被调用,请在 someView().onAppear{ } 中调用您的函数,它将完美地工作。 - Mir
@MirKaram 这应该不是问题。我认为这是特定情况下的问题。如果您像 _bodyText = State(initialValue: "Hello Swift !") 这样初始化 bodyText,它就可以工作了。 - G.Abhisek
1个回答

6
这篇文档明确指出:

你只能从视图的 body 中或被其调用的方法中访问 state 属性。因此,将 state 属性声明为 private 可以防止视图的客户端访问它们。在任何线程中更改 state 属性是安全的。

也就是说,在你的 initsomePublishSubject.sink 中修改 state 是不允许的。

1
有没有特别的原因为什么会这样? - G.Abhisek
1
@G.Abhisek 再次提醒,正如文档所述,“SwiftUI 管理您声明为状态的任何属性的存储”,因此如果您在 body 之外更改 State,则不会影响由 SwiftUI 管理的 State。您可以在 mutating func setUpBinding 中打印状态,即使您更改了值,但打印出来的值仍然是旧值。 - JIE WANG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接