Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: How to read standard output in a child process without waiting for process to finish

Tags:

swift

cocoa

I have an external console application (on OS X) that emits a sequence of integers from 1 to 100 to standard output, roughly once every second.

I Swift, I need to use that stream of numbers in order to update a progress indicator.

Here is the code that I have so far:

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)
    }
}

The code works—that is, it reads the output from the command-line utility and modifies the progress indicator accordingly—but it makes all the changes after the utility quits (and makes my UI wait in the meantime).

How would I set it up so that it reads the output from the background application and updates the progress indicator in real-time?

like image 637
AthanasiusOfAlex Avatar asked Nov 20 '15 06:11

AthanasiusOfAlex


1 Answers

You are reading synchronously on the main thread, therefore the UI is not updated until the function returns to the main loop.

There are (at least) two possible approaches to solve the problem:

  • Do the reading from the pipe on a background thread (e.g. by dispatching it to a background queue – but don't forget to dispatch the UI updates to the main thread again).
  • Use notifications to read asynchronously from the pipe (see Real time NSTask output to NSTextView with Swift for an example).
like image 167
Martin R Avatar answered Sep 24 '22 04:09

Martin R