Swift:如何在不等待进程完成的情况下读取子进程中的标准输出

亚撒纳修斯·亚历克斯

我有一个外部控制台应用程序(在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等待)。

我将如何设置它,以便它读取后台应用程序的输出并实时更新进度指示器?

更新

供以后参考,下面是我如何使其最终工作(现在已针对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%。

马丁·R

您正在主线程上同步读取,因此直到函数返回主循环后,UI才会更新。

有(至少)两种可能的方法来解决此问题:

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不等待-n的情况下以bash等待任何单个子进程终止?

如何在不阻塞Rust的情况下读取子进程的输出?

如何从bash中的子进程实时读取标准输出

如何在不触发子进程“退出”事件的情况下杀死子进程?

如何在不关闭主程序的情况下终止Firefox中的子进程

如何在不成为子进程的情况下从终端打开进程?

如何在不杀死子进程的情况下杀死父shell脚本进程?

如何在不破坏主脚本的情况下用Ctrl + C停止子进程并将子输出流传输到PowerShell中的主脚本?

如何在不等待其他操作完成的情况下更新视图

C#如何在不等待异步完成的情况下启动异步方法?

可以在不等待进程完成的情况下调用subprocess.call吗?

如何在没有其他进程重叠的情况下从进程中打印内容?

从线程中的子进程标准输出读取时的随机行为

如何在不等待的情况下命名管道

如何在不等待的情况下从渠道获取价值

如何在不等待的情况下启用systemd的服务?

如何在不等待的情况下运行Asyncio任务?

如何在不等待它在php中完成的情况下调用函数?

如何在不枚举进程的情况下通过C ++从Windows中的进程ID获取进程名称?

如何在不等待的情况下安全地在C#中调用异步方法

如何在仍在运行的标准输入中写入进程标准输入并从其标准输出中读取?

如何在不使用shell = True的情况下执行此Python子进程调用?

子进程失去了焦点。如何在不打扰用户的情况下找回它?

如何在没有信号的情况下监视子进程?

在C中给定父PID的情况下如何获取所有子进程的PID

如何在终止前从生成的子进程中获取实时标准输出数据?

读取正在等待输入的生成进程的标准输出

如何在不杀死javaw.exe的情况下杀死Windows中的Java进程?

我如何在不使用kill的情况下杀死Linux中的进程?