SwiftUI TextField 在变量更改时不刷新

SwiftUI TextField not Refreshing on Variable Change

我在 List 内有 TextFieldNavigationView 内,声明如下:

NavigationView {
    List {
        Section("Item Name") {
            TextField("", text: $itemName)
                .textInputAutocapitalization(.sentences)
                .disableAutocorrection(false)
                .textFieldStyle(.plain)
        }
    }
}

NavigationView.onAppear 方法中,我设置了用 @State 声明的文本字段的文本变量,如下所示:

@State var itemName: String = ""

和:

.onAppear {
    itemName = "Hello, World!"
}

文本设置正确,但文本字段不刷新。我知道是因为我可以访问文本字段的文本 属性 并获取更新后的值,当用户点击文本字段进行编辑时,文本突然出现。

在我看来,变量更改时文本字段更新其视图是个问题。我是否必须调用与 UIKit 的 layoutSubviews 等效的 SwiftUI?还是我声明我的 itemName 变量错误?

最小可重现示例 (MRE):

struct ItemView: View {

    @State var itemName: String = ""

    var body: some View {
        NavigationView {
            List {
                Section("Item Name") {
                    TextField("", text: $itemName)
                        .textInputAutocapitalization(.sentences)
                        .disableAutocorrection(false)
                        .textFieldStyle(.plain)
                }
            }
            .navigationTitle("Item")
        }
        .onAppear {
            itemName = "Hello, World!"
        }
    }
}

如有任何帮助,我们将不胜感激。

它在预览中运行良好,但我进行了下一步并在模拟器中对其进行了测试,但它失败了。这使我意识到问题所在。我们在从 .onAppear() 开始的动画中看到了很多这种情况。在视图实际显示在屏幕上之前设置视图并调用 .onAppear(),导致无法从 .onAppear() 更新。几乎可以将其视为竞争条件。在调用更新之前必须设置视图并显示在屏幕上,并且需要额外的周期来执行此操作。因此修复很简单:

.onAppear {
    DispatchQueue.main.asyncAfter(deadline: .now()){
        itemName = "Hello, World!"
    }
}

将其包裹在 DispatchQueue.main.asyncAfter(deadline:) 中。这给了它时间来避免这个问题。

我也能够重现它。我同意 Yrb,似乎 onAppear 中的状态突变发生在 TextField 的更新期间,因此文本字段没有从状态中获取新值。

我能够修复它的另一种方法是将状态突变从 NavigationView.onAppear 修饰符移动到 TextField.onAppear 修饰符。如果这样做,就不需要 DispatchQueue.main.async 因为 SwiftUI 会正确同步 onAppear 块的执行与文本字段的更新。