为什么把属性改成 @Published会导致SwiftUI无法触发UI更新?

编程语言 2026-07-09

在我正在开发的一个应用中,我添加了一个TextEditor字段,用来显示应用文档的模型对象中 @Published Text属性的内容。

以下是模型对象的相关部分:

final class DrawingInfo: ObservableObject, Codable {
    // Items saved with Codable
    @Published var title: String
    @Published var text: String
    @Published var toggleIsOn: Bool = false
    let imageSize: CGSize
    @Published var backgroundColor = Color.white
    @Published var texAspect: Float = 1.0
    @Published var linePlacement: Float = 0

    // ...
}

ContentView看起来是这样的:

    var body: some View {
        VStack {
            VStack {
                DrawingView(drawingInfo: $drawingInfo)
                    .frame(width: DrawingInfo.defaultSize.width, height: DrawingInfo.defaultSize.height)
                    .border(Color.blue, width: 4)
                    .aspectRatio(drawingInfo.imageSize, contentMode: .fit)
                TextEditor(text: $drawingInfo.text)
                    .frame(maxHeight: 50)
                HStack {
                    Button("Test") {
                        drawingInfo.text += " Extra words."
                    }

                    Toggle(isOn: $drawingInfo.toggleIsOn) {
                        Text("Toggle is on")
                    }
                    .frame(maxWidth: 200, alignment: toggleAlignment)

                    Slider(value: $drawingInfo.linePlacement, in: -1...1) {

                    }
                    .frame(maxWidth: 200)
                }
            }
        }
    }
}

当你点击“Test”按钮时,它会把字符串“ Extra Words.”追加到模型的text属性中。

然而,我的TextEditor在你对模型的某个 @Published属性再次进行修改之前(例如点击Toggle或调整滑块),不会更新来反映这些更改。

我猜这是因为按钮的闭包直接修改了 text 属性,而不是通过模型的绑定进行修改。

我该如何修改按钮的闭包,使我的TextEditor能够捕捉到 text 属性的变化?是否需要设置一个Combine发布者来触发一个变化?

你可以在Github上查看该项目,链接如下:https://github.com/DuncanMC/DrawingApp.git

解决方案

我给这个问题点了踩,因为你的代码在这里不完整,无法令人满意地回答你的问题;需要去Github才能看到代码。

话虽如此,我看了Github,发现其实不需要把 DrawingInfo 传入到 ContentView。相反,如果你打算在 ContentView 中实例化它,就把 drawingInfo @ObservableObject 写成你需要的形式,或者把它设为 @EnvironmentObject,并通过 .environment 修饰符传递给 ContentView,以便在各处使用同一个实例。

备选方案

以下是一个自包含的代码示例:

final class DrawingInfo: ObservableObject {
    @Published var title: String
    @Published var text: String
    @Published var toggleIsOn: Bool = false
    let imageSize: CGSize
    @Published var backgroundColor = Color.white
    @Published var texAspect: Float = 1.0
    @Published var linePlacement: Float = 0

    init(title: String, text: String, toggleIsOn: Bool, imageSize: CGSize, backgroundColor: Color = Color.white, texAspect: Float, linePlacement: Float) {
        self.title = title
        self.text = text
        self.toggleIsOn = toggleIsOn
        self.imageSize = imageSize
        self.backgroundColor = backgroundColor
        self.texAspect = texAspect
        self.linePlacement = linePlacement
    }
}

struct ContentView: View {
    @ObservedObject var drawingInfo = DrawingInfo(title: "title", text: "text", toggleIsOn: false, imageSize: CGSize(width: 300, height: 300), texAspect: 10, linePlacement: 10)
    @State var toggleAlignment: Alignment = .center
    var body: some View {
        VStack {
            TextEditor(text: $drawingInfo.text)
                .frame(maxHeight: 50)
            HStack {
                Button("Test") {
                    drawingInfo.text += " Extra words."
                }

                Toggle(isOn: $drawingInfo.toggleIsOn) {
                    Text("Toggle is on")
                }
                .frame(maxWidth: 200, alignment: toggleAlignment)

                Slider(value: $drawingInfo.linePlacement, in: -1...1) {

                }
                .frame(maxWidth: 200)
            }
        }
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章