SwiftUI修改@Published属性无法触发UI更新,如何解决?
问题与解决方案
问题描述
我正在开发一款应用,添加了一个TextEditor字段,用于显示应用文档Model对象中@Published修饰的text属性内容。
Model对象相关代码:
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”按钮时,会向model的text属性追加字符串“ Extra words.”,但TextEditor不会立即更新,直到修改其他@Published属性(如点击Toggle或调整Slider)才会刷新。推测是因为按钮闭包直接修改text属性,而非通过model的绑定进行更改,想知道如何修改按钮闭包让TextEditor能实时响应text属性的变化?是否需要设置Combine发布者来触发更新?
解决方案
不需要额外设置Combine发布者,两种简单修改方式即可解决:
方式一:通过绑定的wrappedValue修改
直接使用$drawingInfo.text的绑定对象来修改值,确保发布事件被SwiftUI正确捕获:
Button("Test") { $drawingInfo.text.wrappedValue += " Extra words." }
方式二:在Model内封装修改方法
在DrawingInfo类中添加专门的方法来修改text,这种方式更符合MVVM的封装原则,同时能确保更新事件正常触发:
final class DrawingInfo: ObservableObject, Codable { // 原有属性... func appendToText(_ string: String) { text += string // 若@Published未自动触发更新(极少出现),可手动调用以下代码强制触发: // objectWillChange.send() } }
然后在按钮闭包中调用该方法:
Button("Test") { drawingInfo.appendToText(" Extra words.") }
原因解析
直接修改drawingInfo.text时,虽然@Published会自动发送变更事件,但在某些场景下,SwiftUI可能未正确追踪到该属性的绑定关联,导致视图未及时刷新。通过绑定对象修改或封装方法,能确保变更事件被SwiftUI正确识别,从而实时更新TextEditor的显示内容。
内容的提问来源于stack exchange,提问作者Duncan C
相关产品推荐
相关产品推荐

