Multithreading Swift:如何将工作线程放到单独的线程中,在主视图中显示结果?

Multithreading Swift:如何将工作线程放到单独的线程中,在主视图中显示结果?,multithreading,swiftui,uikit,worker,long-running-processes,Multithreading,Swiftui,Uikit,Worker,Long Running Processes,我想知道是否有一种简单的方法可以做到这一点:将一个长期运行的worker放在一个单独的线程中,这样就不会阻塞UI。并在主视图中显示结果。在SwiftUI或UIKit下。我在网上发现的一切都非常复杂。或者在Swift中是否有完全不同的方法 我制作了一个简约的Python程序来展示我想要做什么。它以MacOS显示WiFi信号强度 import time import sys import subprocess from PyQt5.QtWidgets import QApplication, QWi

我想知道是否有一种简单的方法可以做到这一点:将一个长期运行的worker放在一个单独的线程中,这样就不会阻塞UI。并在主视图中显示结果。在SwiftUI或UIKit下。我在网上发现的一切都非常复杂。或者在Swift中是否有完全不同的方法

我制作了一个简约的Python程序来展示我想要做什么。它以MacOS显示WiFi信号强度

import time
import sys
import subprocess
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout
from PyQt5.QtCore import QObject, pyqtSignal, QThread

class Worker(QObject):
    send_output = pyqtSignal(str)
    def __init__(self):
        super().__init__()

    def worker(self):
        while True:
            _out = subprocess.check_output(
                ["/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport",
                 "-I"])\
                .decode("utf-8")
            self.send_output.emit("RSSI: " + _out.splitlines()[0][-3:] + " dBm")
            time.sleep(2)

class MainWindow(QWidget):
    do_work = pyqtSignal(object)
    def __init__(self):
        super().__init__()

        self.label = QLabel()
        layout = QHBoxLayout()
        self.setLayout(layout)
        layout.addWidget(self.label)
        self.show()

        self.app_thread = QThread()
        self.app = Worker()
        self.app.moveToThread(self.app_thread)
        self.app.send_output.connect(self.output_label)
        self.app_thread.started.connect(self.app.worker)
        self.app_thread.start()

    def output_label(self, _str):
        self.label.setText(_str)

if __name__ == '__main__':
    application = QApplication(sys.argv)
    mainwindow = MainWindow()
    sys.exit(application.exec())

我现在正想办法进入斯威夫特。这很令人兴奋,但确实是件大事。提前谢谢

这是一个非常宽泛的问题,所以我也将回答相当宽泛的问题

是的,您可以在单独的线程中运行任务,然后将数据返回到主线程。有很多方法可以做到这一点,常见的方法是
DispatchQueue

让我们举一个过于简化的例子(绝对不是指真实世界的代码):

在本例中,当视图出现时,任务通过
DispatchQueue
在后台线程中运行。在本例中,我只是利用了这样一个事实:如果打印到控制台上一百万次,那么这是一个相当昂贵的操作

完成后,它将发回主线程并更新状态变量中的结果

DispatchQueue
不是特定于UIKit或SwiftUI的——使用SwiftUI将演示放在一起最简单


如果您真的要开始编写代码来实现这一点,您可能希望对DispatchQueues如何工作进行一些研究,包括使用哪个队列、是否创建自己的队列、是否希望按顺序完成任务等,但出于这样一个广泛问题的目的,即这是否可以完成(以及如何容易完成),这至少说明了基本情况。

非常感谢您的快速回复。是的,我一定会进入DispatchQueue docu。是的,打印效果很好。这不是问题所在。但对于我的情况:我想在worker中的每次迭代之后更新UI视图。在辅助进程完成后不会进行。没问题——在循环/任务中调用DispatchQueue.main.async{}。是的,在此期间我自己也尝试过。非常有效。这就是我想要的!!!我很高兴。现在,对我来说,深入了解如何和为什么等是有意义的。我真的很喜欢Swift的概念。特别是在数据类型安全方面。但这确实是一个巨大的问题,很难从哪里开始。但你告诉了我重点。非常感谢你!!
struct ContentView : View {
    @State var result = ""
    
    var body: some View {
        Text("Result: \(result)")
            .onAppear {
                DispatchQueue.global(qos: .background).async {
                    //do your long-running code
                    var innerResult = 0
                    for i in 0...1000000 {
                        innerResult += 5
                        print(i)
                        //use DispatchQueue.main.async here if you want to update during the task
                    }
                    
                    //update at the end:
                    DispatchQueue.main.async {
                        result = "Done! \(innerResult)"
                    }
                }
            }
    }
}