在 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"
}
}
}
我有一个后台任务需要向打开的对话框显示值。我阅读了很多关于此任务的资料,并根据我的需要调整了教程。但是不管我的尝试如何,在任务完成并且控件回到 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"
}
}
}