SwiftUI从后台进程发布到主视图

问题描述

我正在尝试将数据从后台运行循环获取到主视图。

我可以看到计数器将递增(在终端中打印),但是视图不会刷新当前值。每次显示的值仍为零。

我的代码段如下:

struct ContentView: View {
    @EnvironmentObject var loop : Loop
    
    var body: some View {
        vstack {
            Text("Content View")
            LoopView()
        }
    }
}
struct LoopView: View {
    @EnvironmentObject var loop : Loop
    
    var body: some View {
        vstack {
            Text("Loop View")
            HStack {
                Text("i = ")
                Text("\(loop.i)")
            }
        }
    }
}
class Loop: ObservableObject {
    @Published var i: Int
    
    func startLoop() {
        while true {
            print("i = \(self.i)")
            self.i += 1
            
            sleep(1)
        }
    }
    
    init() {
        dispatchQueue.main.async {
            self.startLoop()
        }
    }
}

解决方法

这是因为您的sleep实际上在主线程(DispatchQueue.main)上运行。如果您确实要使用sleep,请在后台运行DispatchQueue.global()。但是随后您需要再次使用DispatchQueue.main来更新@Published变量:

class Loop: ObservableObject {
    @Published var i: Int

    func startLoop() {
        while true {
            print("i = \(self.i)")
            DispatchQueue.main.async {
                self.i += 1
            }

            sleep(1)
        }
    }

    init() {
        DispatchQueue.global(qos: .background).async {
            self.startLoop()
        }
    }
}

或者,您可以查看重复计时器,它将为您完成工作: