Swift:如何在子进程中读取标准输出而无需等待进程完成
发布时间:2020-12-14 02:25:16 所属栏目:百科 来源:网络整理
导读:我有一个外部控制台应用程序(在OS X上),它发出一系列从1到100到标准输出的整数,大约每秒一次. 我Swift,我需要使用该数字流来更新进度指示器. 这是我到目前为止的代码: class MasterViewController: NSViewController {@IBOutlet weak var progressIndicator
我有一个外部控制台应用程序(在OS X上),它发出一系列从1到100到标准输出的整数,大约每秒一次.
我Swift,我需要使用该数字流来更新进度指示器. 这是我到目前为止的代码: class MasterViewController: NSViewController { @IBOutlet weak var progressIndicator: NSProgressIndicator! override func viewDidLoad() { super.viewDidLoad() let task = Process() task.launchPath = "/bin/sh" task.arguments = ["-c","sleep 1; echo 10 ; sleep 1 ; echo 20 ; sleep 1 ; echo 30 ; sleep 1 ; echo 40; sleep 1; echo 50; sleep 1; echo 60; sleep 1"] let pipe = Pipe() task.standardOutput = pipe task.launch() let data = pipe.fileHandleForReading.readDataToEndOfFile() if let string = String(data: data,encoding: String.Encoding.utf8) { print(string) } } 代码工作 – 也就是说,它从命令行实用程序读取输出并相应地修改进度指示器 – 但它在实用程序退出后进行所有更改(并使我的UI在此期间等待). 我如何设置它以便从后台应用程序读取输出并实时更新进度指示器? UPDATE 为了将来的参考,以下是我最终如何使用它(现在为Swift 3更新): class ViewController: NSViewController { @IBOutlet weak var progressIndicator: NSProgressIndicator! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. let task = Process() task.launchPath = "/bin/sh" task.arguments = ["-c","sleep 1; echo 10 ; sleep 1 ; echo 20 ; sleep 1 ; echo 30 ; sleep 1 ; echo 40; sleep 1; echo 50; sleep 1; echo 60; sleep 1"] let pipe = Pipe() task.standardOutput = pipe let outHandle = pipe.fileHandleForReading outHandle.waitForDataInBackgroundAndNotify() var progressObserver : NSObjectProtocol! progressObserver = NotificationCenter.default.addObserver( forName: NSNotification.Name.NSFileHandleDataAvailable,object: outHandle,queue: nil) { notification -> Void in let data = outHandle.availableData if data.count > 0 { if let str = String(data: data,encoding: String.Encoding.utf8) { if let newValue = Double(str.trimEverything) { self.progressIndicator.doubleValue = newValue } } outHandle.waitForDataInBackgroundAndNotify() } else { // That means we've reached the end of the input. NotificationCenter.default.removeObserver(progressObserver) } } var terminationObserver : NSObjectProtocol! terminationObserver = NotificationCenter.default.addObserver( forName: Process.didTerminateNotification,object: task,queue: nil) { notification -> Void in // Process was terminated. Hence,progress should be 100% self.progressIndicator.doubleValue = 100 NotificationCenter.default.removeObserver(terminationObserver) } task.launch() } override var representedObject: Any? { didSet { // Update the view,if already loaded. } } } // This is just a convenience extension so that I can trim // off the extra newlines and white spaces before converting // the input to a Double. fileprivate extension String { var trimEverything: String { return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } 现在,进度条进展到60%,然后在子进程完成后跳转到100%.
您正在主线程上同步读取,因此在函数返回主循环之前不会更新UI.
有(至少)两种可能的方法来解决问题: >在后台线程上从管道读取(例如通过将其分派到后台队列 – 但不要忘记 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |