2

Since the results to a ping can take more than 4 seconds (depending on the amount of hops), I get the spinning colour wheel (beachball) which normally indicates that the program has locked up or not functioning.

The app does continue with the spinning colour wheel, and finishes with the results in the textbox. Is there a way to get rid of the "beachball"?

I Debugged by printing out the results to each variable. The beachball shows up after the "let handle1 = pipe.fileHandleForReading" has executed. I tried Grand Central Dispatch (GCD) but still get the same results.

// Built using X-Code Version 8.2.1 - Swift Version 3.0.2

// Text view for results (display)
@IBOutlet weak var Results: NSTextField!

// Start button to execute ping
@IBAction func startButton(_ sender: Any)
{
    cmdPing()
}

// Global variables
var myArg = ""
var shellResults = ""

func cmdPing()
{
    // Step 1
    myArg = "ping -c 10 www.google.com"
    shellResults = getPing(shellArgs: myArg)
    Results.stringValue = shellResults

    // Step 2
    myArg = "ping -c 10 127.0.0.1"
    shellResults = getPing(shellArgs: myArg)
    Results.stringValue = shellResults

}


// function that executes a shell command and returns its value (myArg)
func getPing(shellArgs: String) -> String
{
    let task:Process = Process()
    let pipe:Pipe = Pipe()
    task.launchPath = "/bin/sh"
    task.arguments = ["-c", shellArgs]
    task.standardOutput = pipe
    task.launch()
    let handle1 = pipe.fileHandleForReading
    let data1 = handle1.readDataToEndOfFile()
    let result1 = NSString(data: data1, encoding: String.Encoding.utf8.rawValue)
    let trimmed1 = (result1! as NSString).trimmingCharacters(in: NSCharacterSet.whitespaces)
    shellResults = trimmed1
    task.waitUntilExit()
    return shellResults
}

I do get the results in the textbox. What would be nice if it can be done would be to show each line (hop) in the textbox during each ping without the "beachball". Any help would be appreciated.

Robert
  • 21
  • 4
  • Found the answer to my question thanks to Patrick F. from the thread: Real time NSTask output to NSTextView with Swift [link] (https://stackoverflow.com/questions/29548811/real-time-nstask-output-to-nstextview-with-swift) – Robert Jun 21 '19 at 14:11

1 Answers1

0

This is what works. It will execute a command and return each hop in the textview or scrollview window. That will get rid of the spinning "beachball". Added a counter or you could do a loop to continue your many tasks (command pings)

func getPing(shellArgs: String)
{

    let task = Process()
    task.launchPath = "/bin/sh"
    task.arguments = ["-c", shellArgs]

    let pipe = Pipe()
    task.standardOutput = pipe
    let outHandle = pipe.fileHandleForReading
    outHandle.waitForDataInBackgroundAndNotify()

    var obs1 : NSObjectProtocol!
    obs1 = 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 = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
            {
                // place data (str) in Results (textview) window
                self.Results.stringValue += "\(str)"
            }
            outHandle.waitForDataInBackgroundAndNotify()
        }
        else
        {
            print("EOF on stdout from process")
            NotificationCenter.default.removeObserver(obs1)
        }
    }

    var obs2 : NSObjectProtocol!
    obs2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification, object: task, queue: nil)
    {
        notification -> Void in print("terminated")
        NotificationCenter.default.removeObserver(obs2)
        if self.pingCount < 3
        {
            // add counter and continue for other commands (steps)
            self.pingCount += 1
            self.cmdPing()
        }
        else
        {
            // end task
            task.terminate()
        }
    }
    task.launch()
}
Robert
  • 21
  • 4