Swift   发布时间:2022-03-31  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Swift:如何在子进程中读取标准输出而无需等待进程完成大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

我有一个外部控制台应用程序(在OS X上),它发出一系列从1到100到标准输出的整数,大约每秒一次. 我Swift,我需要使用该数字流来更新进度指示器. 这是我到目前为止的代码: class MasterViewController: NSViewController { @IBOutlet weak var progressInDicator: NSProgressInDicator! ov
我有一个外部控制台应用程序(在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.

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

>在后台线程上从管道读取(例如通过将其分派到后台队列 – 但不要忘记
再次将uI更新分派给主线程).
>使用通知从管道异步读取(请参阅
Real time NSTask output to NSTextView with Swift为例).

大佬总结

以上是大佬教程为你收集整理的Swift:如何在子进程中读取标准输出而无需等待进程完成全部内容,希望文章能够帮你解决Swift:如何在子进程中读取标准输出而无需等待进程完成所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。