Real time NSTask output to NSTextView with Swift

The Beanstalk picture The Beanstalk · Apr 9, 2015 · Viewed 8.5k times · Source

I'm using an NSTask to run rsync, and I'd like the status to show up in the text view of a scroll view inside a window. Right now I have this:

let pipe = NSPipe()
task2.standardOutput = pipe
task2.launch()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: NSASCIIStringEncoding)! as String

textView.string = output

And that get's me the some of the statistics about the transfer, but I'd like to get the output in real time, like what get's printed out when I run the app in Xcode, and put it into the text view. Is there a way to do this?

Answer

Kametrixom picture Kametrixom · Jun 29, 2016

Since macOS 10.7, there's also the readabilityHandler property on NSPipe which you can use to set a callback for when new data is available:

let task = NSTask()

task.launchPath = "/bin/sh"
task.arguments = ["-c", "echo 1 ; sleep 1 ; echo 2 ; sleep 1 ; echo 3 ; sleep 1 ; echo 4"]

let pipe = NSPipe()
task.standardOutput = pipe
let outHandle = pipe.fileHandleForReading

outHandle.readabilityHandler = { pipe in
    if let line = String(data: pipe.availableData, encoding: NSUTF8StringEncoding) {
        // Update your view with the new text here
        print("New ouput: \(line)")
    } else {
        print("Error decoding data: \(pipe.availableData)")
    }
}

task.launch()

I'm surprised nobody mentioned this, as it's a lot simpler.