在 SwiftUI 中以开放形式显示来自后台任务的消息

Show messages in open form from background task in SwiftUI

我有一个后台任务需要向打开的对话框显示值。我阅读了很多关于此任务的资料,并根据我的需要调整了教程。但是不管我的尝试如何,在任务完成并且控件回到 from 控件之前没有更新。

所以我在内容视图中所做的,我将其定义为:

struct ContentView: View {
    @StateObject var infoText    = InfoTextObject()

类型定义如下:

class InfoTextObject: ObservableObject {
    @Published var text = ""
}

为了在 SwiftUI 中定义它,我定义了那个结构,因为 类 是不允许的:

// small view with text message area
public struct InfoView: View {
    @ObservedObject var it: InfoTextObject
    
    public var body: some View {
        TextField("Infos ...", text: $it.text)
            .frame(alignment: .topTrailing)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .fixedSize(horizontal: false, vertical: false)
            .disabled(true)
    }
}

表单的正文定义如下所示

var body: some View {
        VStack(alignment: .leading)
        {
...
            InfoView(it: infoText)
        }

最后,调用新消息更新屏幕的函数如下所示:

// function to display any text in the view
func DisplayMessage(infoTextObject: InfoTextObject, _ text: String = "", debugMode : Bool = false) {
    DispatchQueue.main.async {
        infoTextObject.text = text
    }
}

对我来说,对于这样一个简单而平常的任务来说,这看起来非常复杂。但即使它不更新。 :-(

有什么提示吗?

很难判断发生了什么,因为您向我们展示的代码不是您正在使用的代码。 这是在模拟后台进程中更新 txt 的代码示例。

struct ContentViewsdsds: View {
    @State var infoText = ""  
    
    var body: some View {
        VStack {
            InfoView(txt: $infoText)
        }
    }
}

struct InfoView: View {
    @Binding var txt: String 
    
    var body: some View {
        TextField("Infos ...", text: $txt)
            .frame(alignment: .topTrailing)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .fixedSize(horizontal: false, vertical: false)
            .disabled(true)
        Button(action: { DisplayMessage(infoText: $txt, "new message to display") }){
            Text("Click for background task")
        }
    }

}

// simulating reporting updates during a long background process
func DisplayMessage(infoText: Binding<String>, _ text: String = "", debugMode : Bool = false) {
    infoText.wrappedValue = text
    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 2) {
        DispatchQueue.main.async {
            infoText.wrappedValue = "processing"
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            infoText.wrappedValue = "getting there"
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            infoText.wrappedValue = "close to finishing"
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
            infoText.wrappedValue = "all done"
        }
    }
}